Egress hold: back-burner fix plan (Step0 diagnose / Step1 one-const patch / Step3 device fallback)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# Back-burner plan: honor the ~30s customer-egress hold
|
||||
|
||||
Status: BACK BURNER (not started). Context in NET-NOTES.md
|
||||
("EGRESS DELAY = COMPILED IN, TWO-PHASE").
|
||||
|
||||
## Problem restated
|
||||
|
||||
The pod's StopMission close is a two-stage, re-entrant handler (byte-identical
|
||||
in BTLIVE May-96 / BTRAVINE Sep-96 / BTDAVE / Rel410, so not a build regression):
|
||||
|
||||
- OUTER handler (Rel410 @0x47c2c4, dispatched): first StopMission sets a flag
|
||||
@[this+0xd4], schedules itself to re-fire in `3.0*timebase + 0.5` (3.0f
|
||||
literal @0x47c350), returns. The +3s RE-ENTRY runs destructive cleanup
|
||||
(0x44e13c, 0x44fa6c, base shutdown via 0x44eeb4) then calls the inner handler.
|
||||
- INNER handler (Rel410 @0x47b864): base shutdown, egress lamps ON
|
||||
(0x47bba8 flag=1; lamps 0x16/0x17/0x1e), schedules a +30s LightsOut/exit
|
||||
(30.0f literal @0x47b8e4).
|
||||
|
||||
Observed: the process is recycled by GO.BAT in ~3.4s (the 3.0f stage). The
|
||||
30s LightsOut is scheduled AFTER teardown has begun, so the exe dies before
|
||||
it fires -- the 30s is effectively dead. Goal: a real ~30s (ideally
|
||||
configurable) floor-lamps-on customer-egress hold before the pod exits.
|
||||
|
||||
Precondition already true: the floor lamp is lit at mission end and through
|
||||
the wait (tap: FLOOR bright at mission end, off at the ~3.4s teardown), so a
|
||||
longer PRE-teardown wait = a longer visible lamps-on egress window.
|
||||
|
||||
## Step 0 -- diagnose the pre-emption (cheapest, do first)
|
||||
|
||||
Confirm WHICH teardown races the 30s and whether it's config-specific before
|
||||
touching the binary.
|
||||
- Run a mission and grep nn.log at close for the "Sending EndMission..."
|
||||
string and any LightsOut trace; timestamp against the RIO-tap lamp events
|
||||
(scratchpad lamp_read.py) and the netnub relaunch.
|
||||
- Test a NON-looping boot (single `netnub -p -f btl4opt` with a DOS `pause`
|
||||
after, NOT loop.bat) so nothing recycles the exe -- if the 30s LightsOut
|
||||
then fires (lamps stay on ~30s), the pre-emption is the GO.BAT loop timing,
|
||||
not an in-handler race, and the "fix" may be purely a loop-conf change.
|
||||
- If lamps still drop at ~3s even without the loop, the destructive cleanup
|
||||
in the outer handler's re-entry is the culprit -> go to Step 1/2.
|
||||
|
||||
## Step 1 -- PREFERRED: one-constant binary patch (extend stage-1 to 30s)
|
||||
|
||||
Rationale: the outer handler's FIRST stage schedules +3s and returns WITHOUT
|
||||
running the destructive cleanup (that's the re-entry). Extending stage-1 from
|
||||
3s to 30s keeps the floor lamps on (already lit) for ~30s before the
|
||||
destructive re-entry -- an authentic egress hold, with a single 4-byte edit.
|
||||
|
||||
- Target (Rel410): the 3.0f literal at VA 0x47c350 -> patch bytes
|
||||
`00 00 40 40` (3.0f) to `00 00 F0 41` (30.0f). Backup first
|
||||
(BTL4OPT.EXE.pre_egress), assert the original bytes before writing, like the
|
||||
RIO/idle patches. Per-build literal addresses: find via stopmission_cmp3.py
|
||||
(it prints the outer handler VA per build: BTRAVINE @0x47c2b0,
|
||||
BTLIVE/BTDAVE @0x48a3c0; the 3.0f `fld` is a few insns in -- confirm with
|
||||
btdis2.py `dis <handler>` then read the `fld dword ptr [X]` operand).
|
||||
- Make it CONFIGURABLE without re-patching: better than a hardcoded 30, tie
|
||||
the value to an env/INI the device already reads, OR expose it via a small
|
||||
device hook (see Step 3). Simplest first cut = hardcode 30.0f and verify.
|
||||
- Verify: RIO tap shows FLOOR lamp on for ~30s post-StopMission before the
|
||||
sweep+exit; console still recovers; net_loop still recycles after.
|
||||
- Risk: LOW. One literal, reversible. Watch that the scheduler is wall/real
|
||||
time not frozen sim-time (Step 0 settles this); if sim-time is frozen at
|
||||
mission end the timer won't advance and this won't help -> Step 2.
|
||||
|
||||
## Step 2 -- ALTERNATIVE: reorder so the inner 30s survives
|
||||
|
||||
If Step 1's stage-1 timer can't be used (e.g. frozen sim-time), instead make
|
||||
the inner handler's existing 30s LightsOut fire before teardown: NOP or move
|
||||
the destructive cleanup calls (0x44e13c/0x44fa6c/base 0x44eeb4) in the outer
|
||||
re-entry so lamps-on + the 30s schedule run first and the process only exits
|
||||
when LightsOut fires. Riskier (control-flow surgery, must not leak resources
|
||||
or hang); needs the disasm of 0x44e13c/0x44fa6c to know what's safe to defer.
|
||||
|
||||
## Step 3 -- FALLBACK: device/GO.BAT egress window (no binary patch)
|
||||
|
||||
If binary patching is undesirable, synthesize the hold outside the game:
|
||||
- net_loop.conf: after the game exits and before netnub relaunch, insert a
|
||||
~30s DOS delay (e.g. a small TSR/CHOICE-style timeout) so the pod idles in
|
||||
the egress window; the vpxlog/RIO device drives the floor lamp ON for that
|
||||
window (device already owns the RIO serial path -- add a "hold floor lamp N
|
||||
seconds on game-exit" hook keyed by an env var, e.g. VWE_EGRESS_MS).
|
||||
- Pro: fully configurable, no game binary change, works across all builds.
|
||||
- Con: the lamp is device-driven, not game-driven -- cosmetic only, and the
|
||||
timing is approximate. Good enough for venue theater.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Do Step 0 first (may reveal it's just a loop-conf issue = free fix). If a real
|
||||
delay is needed, Step 1 (one-constant patch, made configurable) is the clean
|
||||
path; Step 3 is the no-patch fallback. Tools: scratchpad btdis2.py,
|
||||
stopmission_cmp3.py, lamp_read.py. Existing patch-toolchain precedent + backup
|
||||
discipline in tesla-cockpit-emulator-state (RIO EXE patches).
|
||||
Reference in New Issue
Block a user