Sfoglia il codice sorgente

Select cinematic playback overlay instead of loading screen

Millie 2 giorni fa
parent
commit
0412455c8f

+ 4 - 3
Sunrise/src/client/hooks/bootflow/ember_movie_ui.cpp

@@ -7,9 +7,10 @@ namespace {
 hooking::detour::Handle handle{};
 using SelectState=bool(__fastcall*)(void*,int);
 bool __fastcall select_state(void* ui,int requested) noexcept {
-    // E2EAE0 selects 22h when a cinematic is active and C4C070 is false.
-    // The movie component's D8 callback is DD1D10 (false), so this is its
-    // native presentation state. E1CD60 owns window/category transitions.
+    // Use the playback window, not the loading branch of E2EAE0.
+    // 1312540/13126E0 map 21h to cinematic_overlay and 22h to loading.
+    // The direct player has no type-6 controller to advance that branch.
+    // E1CD60 owns window/category transitions; all drawing stays native.
     // Preserve loading/error/menu requests; substitute only normal gameplay.
     const int selected=ember_movies::movie_ui_state(requested,ember_movies::presenting());
     auto original=reinterpret_cast<SelectState>(handle.original);

+ 4 - 3
Sunrise/src/client/hooks/ember_movies/playback_rules.h

@@ -1,11 +1,12 @@
 #pragma once
 #include "ember_movies.h"
 namespace sunrise::client::hooks::ember_movies {
-// E15D50's normal gameplay choices -> E2EAE0's native movie presentation state.
-// Both cinematic states 21h/22h map to native UI category 4 at E2E9F0.
+// E15D50's gameplay choices -> native cinematic_overlay. Category 4 alone
+// does not distinguish playback from loading: 1312540 maps 21h -> window 26
+// (cinematic_overlay), but 22h -> window 29 (loading) at 13126E0.
 constexpr int movie_ui_state(int requested,bool presenting) noexcept {
     return presenting && (requested==0x2B || requested==0x2D || requested==0x2F)
-        ? 0x22 : requested;
+        ? 0x21 : requested;
 }
 constexpr bool can_chain_movies(Owner current,Owner next,Owner firstCompleted,
                                  unsigned previous,unsigned requested,Status state) noexcept {

+ 18 - 0
docs/mission-ember-final-corrections.md

@@ -1,5 +1,23 @@
 # 1AU: movie loader, surge audio and escape explosions
 
+## Correct the cinematic loading state to the playback overlay
+
+The `41e2728` test exposed a specific presentation regression: `presentation_state requested=43 selected=34 applied=34 category=6` at t=281212, followed by valid movie playback. A read-only UI capture found window `80B46D88`, name hash `D505DEBB` = FNV-1(`loading`), above the video, alongside `80BC6681`, name hash `7737E414` = FNV-1(`subtitle_overlay`). Valid 1920x800 surfaces were captured for both movies. The previous verification established category membership, but misidentified state `0x22` as playback.
+
+The complete native mapping is now verified:
+
+| UI state | `1312540` window enum | `13126E0` name | Meaning |
+| --- | --- | --- | --- |
+| `0x21` | 26 | `17A73819` = `cinematic_overlay` | Cinematic presentation |
+| `0x22` | 29 | `D505DEBB` = `loading` | Loading overlay |
+
+Native window manager `1316FC0` reads the UI state, calls those two mappings, and explicitly excludes `0x22` from its cinematic-overlay branch at `1317094`. Selecting `0x22` was therefore instructing it to draw a loading screen. This was not a missing video frame or stalled resource request.
+
+The bridge now substitutes `0x21` for normal gameplay while it owns ending playback. Existing loading/error/menu selections remain native. There is no drawing-layer mask or subtitle/inventory/settings allowlist; the normal UI window manager handles the transition. The native verifier now checks both complete mappings and their authored name hashes, rather than only category 4.
+
+This same live run confirms the handoff repair: STM completed after Escape at t=443950; CNN reached playing at t=444277 and natural EOF at t=649483. Completion was accepted and orbit selection queued at t=649544; native `orbit_setup` arrived at t=653295. Those receipts establish both native movie lifecycles and orbit setup, not unobscured presentation. The new overlay selection still needs visual validation. Evidence is under `build/first-encounter-audit/41e2728-live-20260906-205738/` and `41e2728-ui-windows/`.
+
+
 ## Visible first movie confirmed; second-movie handoff and native presentation
 
 The user confirmed visible STM playback with `15e507e`. Its decoder reached state 5 at t=281733, with all six selected Y/U/V definitions backed by non-null buffers. Native EOF arrived at t=481606. The bridge then stopped at `surfaces_retiring`: no completion was exposed to Lua, so CNN was never requested. This is the second-movie regression, not missing CNN media.

+ 4 - 2
docs/mission-ember-prerendered-ending.md

@@ -49,8 +49,10 @@ The user confirmed both movie audio tracks in sequence and the mission-complete
 
 ## Native cinematic presentation
 
-The previous drawing-layer and Sunrise overlay suppression have been removed. Native UI selector `E2EAE0` uses state `0x22` for an active pre-rendered component: `C4C070` dispatches the component's `D8` query, whose movie implementation (`DD1D10`) returns false. Both native cinematic states (`0x21`, `0x22`) map to UI category 4 at `E2E9F0`.
+The drawing-layer and Sunrise overlay suppression have been removed. The first state-based attempt (`41e2728`) incorrectly selected `0x22`. Although `0x21` and `0x22` both map to UI category 4, they select different windows: native `1312540` and `13126E0` map `0x21` to enum 26 / `cinematic_overlay` (`17A73819`), and `0x22` to enum 29 / `loading` (`D505DEBB`). The live capture confirmed the `loading` window above otherwise valid video and subtitles.
 
-While the ending bridge owns playback, its state hook replaces normal gameplay choices `0x2B/0x2D/0x2F` with `0x22` and calls the original `E1CD60` transition. Other states pass through. This uses native window/category management; neither `132BD80` drawing layer is skipped. Presentation remains active across the STM-to-CNN handoff, then clears on CNN completion or failure. The mapped-image verifier checks the selector, component dispatch and category mapping; visible presentation still requires a fresh test.
+While the ending bridge owns playback, its state hook now replaces normal gameplay choices `0x2B/0x2D/0x2F` with **`0x21`** and calls the original `E1CD60` transition. Other states pass through, including menus and actual loading/error requests. Native window/category management handles the change; neither `132BD80` drawing layer is skipped. Presentation remains active between STM and CNN, then clears on CNN completion or failure. The mapped-image verifier checks the full state-to-window mapping, names and cinematic branch; unobscured video and normal menu behavior still need the next live test.
+
+The `41e2728` run confirmed native CNN playback after STM, CNN natural EOF and immediate orbit selection followed by `orbit_setup`. The loading overlay is the remaining presentation defect captured in that run.
 
 The Lua variable `ember.hud.audience.<region>` only records initialization of the authored objective engagement sensor. It is not a cinematic state. The intro's `set_cinematic_active` enters its authored cinematic controller; reselecting its region for these ending movies would replay/unload mission content and is not part of this change.

+ 2 - 1
tests/ending_retirement_test.cpp

@@ -42,8 +42,9 @@ int main() {
     for (int ui=-1;ui<=0x2F;++ui) {
         assert(movies::movie_ui_state(ui,false)==ui);
         const bool gameplay=ui==0x2B || ui==0x2D || ui==0x2F;
-        assert(movies::movie_ui_state(ui,true)==(gameplay ? 0x22 : ui));
+        assert(movies::movie_ui_state(ui,true)==(gameplay ? 0x21 : ui));
     }
+    assert(movies::movie_ui_state(0x22,true)==0x22); // An actual loading request keeps priority.
     movies::OrbitReturn orbit;
     movies::OrbitObservation inApex{true,true,false,false,true,0,38,38,true};
     using OA=movies::OrbitAction;

+ 21 - 3
tests/verify_ember_movie_native.py

@@ -62,7 +62,7 @@ assert data[0x12045BF:0x12045C6] == bytes.fromhex('48 2b c1 4c 89 40 08')
 assert data[0x4A6340:0x4A6345] == bytes.fromhex('48 8b 41 08 c3')
 ui = signature('Sunrise/src/client/hooks/bootflow/ember_movie_ui.cpp', 'sig')
 assert ui == 0xE1CD60
-# Native cinematic selection: active entry + movie's false D8 callback => state 22h.
+# Native selector's false D8 branch is cinematic LOADING, not ready playback.
 target(0xE2EB75,0,0xC4B760)
 target(0xE2EB8E,0,0xC4C070)
 assert data[0xE2EB97:0xE2EB9C] == bytes.fromhex('bb 22 00 00 00')
@@ -71,7 +71,7 @@ assert data[0x1871FAB:0x1871FB3] == bytes.fromhex('48 8b 94 02 d8 00 00 00')
 assert struct.unpack_from('<Q',data,0x1CDB4E0)[0] == 0x140DDB0F0
 assert struct.unpack_from('<Q',data,0x1CDB4E0-0x48+0xD8)[0] == 0x140DD1D10
 assert data[0xDD1D1C:0xDD1D23] == bytes.fromhex('32 c0 48 83 c4 28 c3')
-# Both authored cinematic UI choices map to category 4; E1CD60 applies it natively.
+# Both cinematic choices map to category 4; that alone did not identify playback.
 for state in (0x21,0x22):
     case=data[0xE2EA70+state+1]
     assert struct.unpack_from('<I',data,0xE2EA48+4*case)[0] == 0xE2EA2A
@@ -82,7 +82,25 @@ target(0xE1CE0F,0,0x1340F00)
 target(0x132B890, 0x353, 0x1278FF0)  # native movie command is queued before either UI layer
 target(0x132B890, 0x3DF, 0x132BD80)
 target(0x132B890, 0x40C, 0x132BD80)
-print('Native pre-rendered cinematic UI state 22h / category 4 verified; no draw suppression.')
+# Follow the actual state -> window enum -> authored window name mapping.
+def fnv1(name):
+    value=0x811C9DC5
+    for byte in name.encode(): value=((value*0x1000193)&0xFFFFFFFF)^byte
+    return value
+for state, enum, branch, name in [(0x21,26,0x13125D0,'cinematic_overlay'),
+                                  (0x22,29,0x131258E,'loading')]:
+    assert struct.unpack_from('<I',data,0x131260C+4*(state+1))[0] == branch
+    assert data[branch] == 0xB8 and struct.unpack_from('<I',data,branch+1)[0] == enum
+    window=struct.unpack_from('<I',data,0x131284C+4*enum)[0]
+    assert data[window:window+2] == bytes.fromhex('8b 05')
+    name_at=window+6+struct.unpack_from('<i',data,window+2)[0]
+    assert struct.unpack_from('<I',data,name_at)[0] == fnv1(name)
+target(0x1317031,0,0x1312540)
+target(0x1317366,0,0x13126E0)
+# The UI explicitly excludes loading state 22h from its cinematic-overlay branch.
+assert data[0x1317094:0x131709A] == bytes.fromhex('41 83 fc 22 74 05')
+assert fnv1('subtitle_overlay') == 0x7737E414
+print('Native UI 21h -> cinematic_overlay; 22h -> loading verified; no draw suppression.')
 for offset, expected in [(0x96, 0x4294D0), (0xD1, 0x423EF0), (0x14C, 0x4312D0), (0x157, 0x435AA0)]:
     target(load, offset, expected)
 for offset, expected in [(0x85, 0x42C650), (0x9F, 0x425310)]: