Audio: subsystem STATE sounds -- GaugeAlarm54 IS a StateIndicator; register Generator/Condenser/Reservoir state (task #50)
The audio subsystem binds AudioStateWatchers (class 28) to per-subsystem state attrs (GeneratorState/CondenserState/ReservoirState) BY NAME. Recovered the watcher TYPE per attribute via a MakeObjectImplementation ClassID trace. Root cause of the subsystem-state crash: the binary's 0x54-byte subsystem alarm (FUN_0041b9ec, reconstructed as GaugeAlarm54) IS a StateIndicator -- its "three sub-indicators" @0x18/0x2c/0x40 are the audio/video/gauge watcher SChains, and level@0x14 is currentState. The reconstruction had modeled that tail as an opaque `_tail`, so the sockets were never constructed -> AddAudioWatcher AV'd on 0xCDCDCDCD. - GaugeAlarm54: give it the three REAL, constructed SChainOf<Component*> sockets + AddAudioWatcher/Video/Gauge; SetLevel now fires the watchers on a level CHANGE (empty sockets = no-op, so the ~all other alarms are unaffected). levelB (weapon LevelCountB "reset source") is left untouched -- weapons unchanged. sizeof stays 0x54 (static_assert holds -> SChainOf<Component*> is 0x14, layout exact). - Register the state attrs -> the subsystem's own alarm (own AttributePointers[] chained to the parent): Generator.GeneratorState->stateAlarm, Condenser. CondenserState->condenserAlarm, Reservoir.ReservoirState->reservoirAlarm. Those alarms are already SetLevel'd by the sim, so the state audio fires on transition. - AudioStateWatcher guard now validates the +0x18 SOCKET (what AddAudioWatcher touches), not the +0 vtable -- GaugeAlarm54 is non-polymorphic at +0 (raw header) but has a real socket at +0x18. audiostate skips 85 -> 10 (only AmmoBin AmmoState/SimulationState left). The Logical/Scalar/Enum subsystem attrs (ReportLeak/GeneratorOn/ConfigureActivePress/ MotionState/SpeedOfTorsoHorizontal/TargetRangeExponent) stay inert (read 0, silent, non-crashing) -- they need backing members in size-locked layouts (a polish wave). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
03f0c21484
commit
5ba541ed56
@@ -883,14 +883,19 @@ AudioStateWatcher::AudioStateWatcher(
|
||||
// at +0x18 -- and AddAudioWatcher would AV in SChainOf::Add. Skip the register
|
||||
// (that subsystem's state audio stays silent) until the subsystem is built; this
|
||||
// is SELF-CLEARING (a real StateIndicator passes). See docs: audio subsystem wave.
|
||||
// Validate the AUDIO SOCKET at +0x18 (what AddAudioWatcher touches), NOT the
|
||||
// object's +0 vtable: a real StateIndicator has a vtable at +0, but the binary's
|
||||
// 0x54 subsystem alarm (GaugeAlarm54) is non-polymorphic there (a raw header) yet
|
||||
// has a real, constructed SChainOf socket at +0x18. A skip means the socket is
|
||||
// unconstructed (null / debug-fill 0xCDCDCDCD) -- the inert pad or a subsystem not
|
||||
// yet reconstructed. Registering there would AV in SChainOf::Add.
|
||||
{
|
||||
unsigned vt = *(unsigned*)attributePointer;
|
||||
unsigned chain = *(unsigned*)((char*)attributePointer + 0x18);
|
||||
if (vt == 0 || vt == 0xCDCDCDCD || chain == 0xCDCDCDCD)
|
||||
if (chain == 0 || chain == 0xCDCDCDCD)
|
||||
{
|
||||
if (getenv("BT_AUDIO_LOG"))
|
||||
DEBUG_STREAM << "[audiostate] skip watcher on unbuilt StateIndicator "
|
||||
<< attributePointer << " (vt=" << (void*)vt << ")\n" << std::flush;
|
||||
<< attributePointer << " (chain=" << (void*)chain << ")\n" << std::flush;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user