mission-ember-final-corrections.md 7.4 KB

1AU: final playback, burn and surge correction

Confirmed failure and plan

The 4f5c706 playtest reached escape, queued STM at t=284067 and submitted it at t=284084. The decoder stayed at state 0. The deeper worker stack contains an exception record: C0000005, instruction game+349D2C, reading address 0x8. Its callers are 41A810 -> 41CB60 -> 41D590 (movie resource lookup, prepare, manager service). This is an access violation during preparation, not an ordinary slow load and not the earlier world-retirement failure.

Read-only residency capture confirms the cause: movie tags 80BCA001/000/003/002 still contain FEFE free-list entries. The package is registered, but these entries were never requested. A package TagHash is already a valid runtime handle; the missing operation is loading, not converting the numeric hash. The package loading and handle guides under Sunrise-docs/refs document that distinction.

Implement and verify the following:

  1. Use the native asynchronous resource-root producer to load each movie and its authored dependency graph. Require the completed root and matching resident wrapper/header before calling the player. Keep the resource request through playback, then release it without a global I/O drain.
  2. Keep STM -> CNN -> mission complete driven by real playback and completion observations. Retain Apex while the videos play, avoiding the independently broken world teardown. Failures must leave the mission incomplete and report a specific cause.
  3. Use one native sunburn effect attachment for the climb and escape. Change its filter at deposit; disable the separate damage-volume object. Preserve native damage timing, duplicate protection and detachment instead of applying an additional damage multiplier.
  4. Advance only the surge sequence request by four seconds. Keep the visual/mechanical clock at 14 seconds closed, 6 seconds surge, 10 seconds cooling.
  5. Build, run native ABI checks and mission regression suites, then install with backups and hashes while the game is closed. The user launches the game.

Executed implementation

Native movie resource lifetime

The bridge follows the existing startup loader B46E10:

  • 4294D0() gets the resource manager.
  • 423EF0(manager, &root, 8, 2, 0, "mission_ember_movie") creates an asynchronous root.
  • 4312D0(rootObject, {2, movieTag}) adds the authored resource.
  • 435AA0(manager, rootHandle) submits the request.
  • 42C650(rootObject) observes native root state: 1 pending, 2 completed, 3 failed.
  • The wrapper must be class 80808495; its +8 child must be the exact corresponding class 80808499 movie header; the media reference must be present.
  • Only then run the existing acquire/play pair 41A3C0 / 41CD20.
  • After the native movie player releases its reference, 425310 disposes the completed request. Pending requests are polled, never synchronously drained on the frame. Failed requests do not award completion.

All callable addresses are resolved through unique native signatures and relative call targets. No hardcoded executable address is called. The saved executable verifies the six resource calls and pool accessor. The existing decoder rules still require state 5 for the exact asset, then native completion; queued and prepared requests cannot complete a movie.

Single sunburn attachment

The placed native sunburn volume's condition component (80B82485, c_condition_vol_component_*) references effect entity 80B82489. That entity carries its own burn logic and visual components (80F7AB1E and 80BEB1C9). The scripted deck heat shimmer (80B3A2A8) is only the visual layer; attaching it alone would not supply burn damage.

A read-only live capture verifies Ember slot 43's source (80B3C0C6, 80809540, +AC8) and its writable attachment template: self+210+relative, with resource 80C1D9E0 at +0. Native 9F2760 -> 56DE00 consumes that template to create an actor's tracked child attachment.

The narrowly scoped hook substitutes resident 80B82489 only during that one source's native attachment call, then restores the template even on exception. It does not modify package data or Foundry's shared resource. Native duplicate checks, attachment registration and removal remain in control. A missing sunburn resource refuses attachment and logs it rather than dereferencing unloaded data.

Lua uses that same slot for the five climb-pipe volumes and, after deposit, the escape rail volume 60/414. It moves the filter with a new revision, never enables a second attachment owner, and keeps SUNBURN_DAMAGE_OBJECT disabled. Completion and checkpoint handling clear/reconcile the attachment through the existing hazard lifecycle. Damage rate and visual behavior still need confirmation in the game; the source/ownership fix is established, not a measured final health-loss rate.

Audio

The sequence request changes from 4000 ms into the closed window to the next timer event (1 ms). This is approximately four seconds earlier. No beam pose, surge, shutter, or cooling duration changes.

Failure cases checked

Case Required behavior
Registered but unloaded movie Request and wait; never call native playback
Partially resident or wrong movie header Keep waiting, then fail on the preparation bound
Native resource load fails Report failure; do not complete mission
Preparation timeout with pending I/O Leave frame responsive; defer disposal until request finishes
Decoder never reaches playback Do not count it as a completed movie
Wrong decoder/asset, world change Fail rather than complete another movie's request
Repeated escape, completion, or hazard callbacks No duplicate movie completion or burn attachment
Deposit Stop beam; move the existing burn to escape bounds; no volume-object damage in parallel
Movie EOF or player skip Confirm native stop before starting the next movie / completing mission
Another mission or another effect source Sunburn substitution does not match

Validation and remaining live test

Release build, 23 portable tests, all five Lua mission suites, and tests/verify_ember_movie_native.py pass. The full route stays within 239 variables, 61 intents/event and four timers. The native test validates signatures, call offsets, table accessor and attachment asset field against the mapped image. The portable cases explicitly reject unloaded/partial/wrong headers and pending disposal, and verify burn source isolation. Lua tests cover single-source damage ownership and the revised audio request timing.

The fix has not yet been confirmed by a fresh game run. Acceptance requires: scorch after deposit with normal damage and clean removal; surge audio aligned with the existing visual; STM begins at escape with moving frames/audio; CNN follows; mission completion occurs only after CNN; both movies can be skipped; no freeze. Expected diagnostics are resource_requested -> resource_ready -> submitted -> playing -> complete -> resource_released (release may log immediately before complete), repeated for movie 2. Burn attaches log ev=ember_sunburn result=attached ... asset=80B82489.

Evidence is saved under build/first-encounter-audit/: direct-movie-stall-4f5c706-20260906-1803.log, movie-stacks-20260906-180532/00000180.bin, direct-movie-20260906-180404/manager.bin, and reactor-runtime-20260906-181944/. These are diagnostics, not a promise that passing offline checks proves rendered playback.