mirror of
https://github.com/sal063/AC6_recomp
synced 2026-08-21 23:00:53 -04:00
Fix KB+M going inert on the ground: heartbeat from every flight state
KB+M's flight heartbeat only came from the main force step, which never runs on the ground, keyboard flight controls were dead until takeoff. Fire it from every state's provider: the alternate ground step (rolling) plus the master updates and ground-state maintainer (standstill).
This commit is contained in:
@@ -159,10 +159,27 @@ void BlendFieldDelta(uint8_t* base, uint32_t ea, float pre, double ratio, const
|
||||
}
|
||||
}
|
||||
|
||||
// Player aircraft chain (static RE): [[[0x826E4E54]+0x29FC4]+0x1008] = player
|
||||
// actor (null until spawned); the flight model is the POINTER at actor+4912 -
|
||||
// the slot every ground-state writer and the actor's own vtable dispatch
|
||||
// load. Used to scope the master-update heartbeat below to the player.
|
||||
uint32_t PlayerFlightModel(uint8_t* base) {
|
||||
const uint32_t sys = rex::memory::load_and_swap<uint32_t>(base + 0x826E4E54);
|
||||
if (sys == 0) return 0;
|
||||
const uint32_t mgr = rex::memory::load_and_swap<uint32_t>(base + sys + 0x29FC4);
|
||||
if (mgr == 0) return 0;
|
||||
const uint32_t actor = rex::memory::load_and_swap<uint32_t>(base + mgr + 0x1008);
|
||||
if (actor == 0) return 0;
|
||||
return rex::memory::load_and_swap<uint32_t>(base + actor + 4912);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PPC_EXTERN_FUNC(__imp__rex_sub_823046A0); // flight-model force step
|
||||
PPC_EXTERN_FUNC(__imp__rex_sub_82329B40); // flight-model input shaping
|
||||
PPC_EXTERN_FUNC(__imp__rex_sub_82305278); // flight-model alternate (ground) force step
|
||||
PPC_EXTERN_FUNC(__imp__rex_sub_82329488); // derived flight-model master update (vt 0x8200FBC0+60)
|
||||
PPC_EXTERN_FUNC(__imp__rex_sub_82306620); // base flight-model master update (vt 0x8200F2A8+60)
|
||||
|
||||
// KB+M context switch (ac6_kbm_input.cpp): the force step is the reliable
|
||||
// "flight sim is stepping" heartbeat (runs per frame for every aircraft,
|
||||
@@ -209,6 +226,77 @@ PPC_FUNC_IMPL(rex_sub_82329B40) {
|
||||
s_logged);
|
||||
}
|
||||
|
||||
// Flight-model alternate force step (0x82305278): the ground variant,
|
||||
// dispatched via vtable+156 instead of the main step while the mode word
|
||||
// [this+332] has bit 0x40 set - the player actor's ground-contact state
|
||||
// (landed / taxiing). The KB+M flight heartbeat must fire from BOTH force
|
||||
// steps: on the ground only this one runs, and without it the flight key set
|
||||
// suspended while landed (WASD fell through to menu keys, throttle dead on
|
||||
// the runway). Pause behavior is preserved: both steps dispatch from the
|
||||
// same master update, which halts with the sim, so the pause menu still gets
|
||||
// the menu key set exactly as before. A ground 30-vs-60 A/B showed no
|
||||
// framerate-dependent taxi acceleration, so unlike the main step this one
|
||||
// needs no accumulator blend - the wrapper is a pass-through.
|
||||
PPC_FUNC_IMPL(rex_sub_82305278) {
|
||||
PPC_FUNC_PROLOGUE();
|
||||
|
||||
ac6KbmNotifyFlightStep();
|
||||
__imp__rex_sub_82305278(ctx, base);
|
||||
}
|
||||
|
||||
// Flight-model master updates: run once per frame per aircraft from the actor
|
||||
// update (the player driver rex_sub_82233FB0 calls vtable+60 unconditionally)
|
||||
// and dispatch the force steps off the mode word inside. There are TWO
|
||||
// implementations behind vtable+60 - 0x82306620 in the base-class vtable
|
||||
// (0x8200F2A8, force steps by ADDRESS in its slots) and 0x82329488 in the
|
||||
// derived vtable (0x8200FBC0, force steps behind thunks); field logs showed
|
||||
// the player's aircraft dispatching the BASE one, so both are wrapped
|
||||
// identically for standstill KB+M coverage: a PARKED aircraft is deactivated
|
||||
// (mode bit 0x80, cleared only once rolling) and steps neither force step, so
|
||||
// the flight heartbeat must come from here. PLAYER-scoped: the chain is null
|
||||
// outside a spawned player, so AI and front-end objects can never hold the
|
||||
// flight context open. Pause safety is field-proven: pausing mid-flight halts
|
||||
// the force-step heartbeat, and in flight the mode word has neither skip bit
|
||||
// set, so if this update kept running while paused it would dispatch the main
|
||||
// step and the heartbeat would never halt - it does, so it halts with the
|
||||
// sim. Like the rest of this file, none of it is gated on the physics fix:
|
||||
// with the unlock off the wrappers are pass-throughs that still notify.
|
||||
static void MasterUpdateEnter(uint8_t* base, uint32_t self) {
|
||||
if (self != 0 && self == PlayerFlightModel(base)) {
|
||||
ac6KbmNotifyFlightStep();
|
||||
}
|
||||
}
|
||||
|
||||
PPC_FUNC_IMPL(rex_sub_82329488) {
|
||||
PPC_FUNC_PROLOGUE();
|
||||
|
||||
MasterUpdateEnter(base, ctx.r3.u32);
|
||||
__imp__rex_sub_82329488(ctx, base);
|
||||
}
|
||||
|
||||
PPC_FUNC_IMPL(rex_sub_82306620) {
|
||||
PPC_FUNC_PROLOGUE();
|
||||
|
||||
MasterUpdateEnter(base, ctx.r3.u32);
|
||||
__imp__rex_sub_82306620(ctx, base);
|
||||
}
|
||||
|
||||
PPC_EXTERN_FUNC(__imp__rex_sub_82233208); // player-actor ground-state maintainer
|
||||
|
||||
// Belt-and-braces standstill heartbeat: rex_sub_82233208 maintains the ground
|
||||
// state (sets/clears mode bit 0x40) and is bl-called from the player-actor
|
||||
// physics driver right after the master update, so the strong override
|
||||
// capture is direct-call-guaranteed even if some third vtable dispatches yet
|
||||
// another master-update variant. It only exists on the player actor (sole
|
||||
// call site is the player driver rex_sub_82233FB0), so no scoping check is
|
||||
// needed, and it halts with the sim like the rest of the driver chain.
|
||||
PPC_FUNC_IMPL(rex_sub_82233208) {
|
||||
PPC_FUNC_PROLOGUE();
|
||||
|
||||
ac6KbmNotifyFlightStep();
|
||||
__imp__rex_sub_82233208(ctx, base);
|
||||
}
|
||||
|
||||
// Mid-asm hook (registered in ac6recomp_config.toml at 0x82304F40, the
|
||||
// `fsubs f11,f11,f9` inside rex_sub_823046A0): f9 holds the vertical
|
||||
// lift-deficit drop about to be subtracted from the velocity that becomes the
|
||||
|
||||
@@ -1241,11 +1241,15 @@ PPC_FUNC_IMPL(rex_sub_82390CE0) {
|
||||
}
|
||||
}
|
||||
|
||||
// Primary flight heartbeat, called from the fps-physics force-step wrapper
|
||||
// (rex_sub_823046A0 in ac6_fps_physics_fix.cpp) - proven to run per frame for
|
||||
// every aircraft in a mission and to halt when the sim halts. The sampler
|
||||
// hook below turned out to be control-mode dependent (never fired in the
|
||||
// M2 round-1 field test), so it stays only as a secondary signal.
|
||||
// Primary flight heartbeat, called from the fps-physics wrappers in
|
||||
// ac6_fps_physics_fix.cpp: the main force step rex_sub_823046A0 (airborne),
|
||||
// the alternate step rex_sub_82305278 (rolling on the ground, mode bit 0x40),
|
||||
// and - player-scoped - the master updates plus the ground-state maintainer,
|
||||
// which still tick at a full standstill where the deactivated model (bit
|
||||
// 0x80) steps neither. All of them halt when the sim halts, so menus and
|
||||
// pause still fall back to the menu key set. The sampler hook below turned
|
||||
// out to be control-mode dependent (never fired in the M2 round-1 field
|
||||
// test), so it stays only as a secondary signal.
|
||||
void ac6KbmNotifyFlightStep() {
|
||||
g_last_flight_ms.store(NowMs(), std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user