From fa3d634ed36a15284ba4e12c99ff3aa15587ac6e Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Mon, 3 Aug 2026 20:33:32 -0500 Subject: [PATCH] #118 crash fix: the eng-eject page gate moves into the game-thread RIO drain The page-gated eject query ran in the window-click thread (PadRIO EmitButton) and dereferenced the TU-local application global -- NULL there under the /FORCE duplicate-symbol layout -> c0000005 at mode-manager +0x50 the moment the operator pressed the eng eject key (field crash, live.log [crash] record). Moved into LBE4ControlsManager::ProcessRIOEvent's ButtonPressedEvent branch, where mode_mask is already resolved on the game thread; PadRIO now only queues events. Same gate semantics (armed + that bank's ENG-page mode bits); verified no-crash + no-eject on the quad page. Co-Authored-By: Claude Fable 5 --- engine/MUNGA_L4/L4CTRL.cpp | 26 ++++++++++++++++++++++++++ engine/MUNGA_L4/L4PADRIO.cpp | 29 +++++------------------------ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/engine/MUNGA_L4/L4CTRL.cpp b/engine/MUNGA_L4/L4CTRL.cpp index 59917b7..5540b95 100644 --- a/engine/MUNGA_L4/L4CTRL.cpp +++ b/engine/MUNGA_L4/L4CTRL.cpp @@ -2630,6 +2630,32 @@ void // Save 'pressed' mode mask for 'release' //---------------------------------------- buttonActivateModeMask[rio_event.Data.Unit] = mode_mask; + + // THE ENG-PAGE EJECT KEY [T3 intent-completion, #118]: side keys + // 0x0B/0x23/0x03 are the eng-page EJECT position (engEject lamp 0x85 + // = kBTEngBankTop-4; the streamed weapon pages route the same key to + // EjectAmmo). Eject was UNFINISHED in the 4.10 binary (the armed + // mode never rose), so the generator-page press has no authored + // route; complete the intent here IN THE DRAIN (game thread -- + // mode_mask in hand; a first cut queried the mode manager from the + // window-click thread and crashed on the unbound TU global): while + // PANIC is armed AND that bank shows an ENG page, forward the press + // as a pilot-keypad key -- the binary's one armed eject binding. + { + const int a = rio_event.Data.Unit; + unsigned engBits = + (a == 0x0B) ? 0x001Eu : // bank 1: eng modes aux 1-4 + (a == 0x23) ? 0x03C0u : // bank 2: eng modes aux 5-8 + (a == 0x03) ? 0x7800u : 0u; // bank 3: eng modes aux 9-12 + if (engBits != 0 + && ((unsigned)mode_mask & 0x200000u) != 0 + && ((unsigned)mode_mask & engBits) != 0) + { + ControlsKey eject_key = '0'; + Check(&keyboardGroup[KeyboardPilot]); + keyboardGroup[KeyboardPilot].ForceUpdate(&eject_key, mode_mask); + } + } break; case RIO::ButtonReleasedEvent: diff --git a/engine/MUNGA_L4/L4PADRIO.cpp b/engine/MUNGA_L4/L4PADRIO.cpp index ceeea75..26ff495 100644 --- a/engine/MUNGA_L4/L4PADRIO.cpp +++ b/engine/MUNGA_L4/L4PADRIO.cpp @@ -475,30 +475,11 @@ void if (address == 0x3D && pressed) EmitKeypad(LBE4ControlsManager::KeyboardPilot, 0); - // THE ENG-PAGE EJECT KEY [T3 intent-completion, 2026-08-03]: physical - // side keys 0x0B / 0x23 / 0x03 are the eng-page EJECT function position - // (engEject lamp 0x85 = kBTEngBankTop - 4; the streamed weapon pages - // route the same key to EjectAmmo msg 0xB, and the lamp-name/function - // columns align key-for-key). On GENERATOR eng pages the shipped stream - // gives this key NO live route (msg 9 -- no handler in any class table): - // eject was UNFINISHED in the 4.10 binary (the permission evaluator was - // dead code, so panic mode never armed in the arcade at all). Complete - // the authored intent: while PANIC mode is armed AND that bank shows an - // ENGINEERING page (kBTEngModeMask bits -- the same per-page gating the - // alarm lamps use), the flashing EJECT key fires the pilot-keypad eject. - // On any other page (quad select, weapon pages) the key keeps its - // authored function -- the two field regressions came from skipping the - // page gate. - if (pressed && (address == 0x0B || address == 0x23 || address == 0x03)) - { - ModeMask mask = application->GetModeManager()->GetModeMask(); - unsigned engBits = - (address == 0x0B) ? 0x001Eu : // bank 1: eng modes aux 1-4 - (address == 0x23) ? 0x03C0u : // bank 2: eng modes aux 5-8 - 0x7800u; // bank 3: eng modes aux 9-12 - if ((mask & 0x200000u) != 0 && ((unsigned)mask & engBits) != 0) - EmitKeypad(LBE4ControlsManager::KeyboardPilot, address & 0xF); - } + // (The ENG-PAGE EJECT KEY intent-completion lives in the game-thread RIO + // drain -- LBE4ControlsManager::ProcessRIOEvent, ButtonPressedEvent -- + // where mode_mask is safely in hand. A first cut queried the mode + // manager HERE, on the window-click thread, and crashed on the unbound + // TU global (field-caught 2026-08-03).) RIOEvent event; event.Type = pressed ? ButtonPressedEvent : ButtonReleasedEvent;