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
@@ -80,6 +80,37 @@ static const Scalar CoolantDrawFloor = 0.0025f; // _DAT_0050e3d8 (zero floor
|
||||
static const Scalar CoolantActiveOn = 0.003f; // _DAT_0050e3d4 (ON threshold)
|
||||
|
||||
|
||||
//###########################################################################
|
||||
// GaugeAlarm54 watcher sockets. The binary's 0x54 alarm (FUN_0041b9ec) IS a
|
||||
// StateIndicator -- its three sub-indicators @0x18/0x2c/0x40 are the audio/
|
||||
// video/gauge watcher chains, level@0x14 is currentState. These out-of-line
|
||||
// bodies let an AudioStateWatcher bind to any subsystem alarm BY NAME
|
||||
// (GeneratorState / CondenserState / ReservoirState / ...); SetLevel fires the
|
||||
// registered watchers on a level change, so the state audio plays on transition.
|
||||
// Empty sockets iterate to nothing, so alarms with no audio watchers are a no-op.
|
||||
//###########################################################################
|
||||
void GaugeAlarm54::AddAudioWatcher(Component *watcher) { audioWatcherSocket.Add(watcher); }
|
||||
void GaugeAlarm54::AddVideoWatcher(Component *watcher) { videoWatcherSocket.Add(watcher); }
|
||||
void GaugeAlarm54::AddGaugeWatcher(Component *watcher) { gaugeWatcherSocket.Add(watcher); }
|
||||
|
||||
void GaugeAlarm54::NotifyWatchers()
|
||||
{
|
||||
Component *watcher;
|
||||
{
|
||||
SChainIteratorOf<Component*> iterator(audioWatcherSocket);
|
||||
while ((watcher = iterator.ReadAndNext()) != NULL) watcher->Execute();
|
||||
}
|
||||
{
|
||||
SChainIteratorOf<Component*> iterator(videoWatcherSocket);
|
||||
while ((watcher = iterator.ReadAndNext()) != NULL) watcher->Execute();
|
||||
}
|
||||
{
|
||||
SChainIteratorOf<Component*> iterator(gaugeWatcherSocket);
|
||||
while ((watcher = iterator.ReadAndNext()) != NULL) watcher->Execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
// HeatableSubsystem
|
||||
@@ -236,6 +267,25 @@ int
|
||||
//#############################################################################
|
||||
// Shared Data Support
|
||||
//
|
||||
// CondenserState -> condenserAlarm (@0x1DC). Chained to HeatSink so the inherited
|
||||
// coolant/temp attrs stay reachable; dense from HeatSink::NextAttributeID.
|
||||
const Condenser::IndexEntry
|
||||
Condenser::AttributePointers[]=
|
||||
{
|
||||
ATTRIBUTE_ENTRY(Condenser, CondenserState, condenserAlarm) // @0x1DC (0x54 StateIndicator-compatible alarm)
|
||||
};
|
||||
|
||||
Condenser::AttributeIndexSet&
|
||||
Condenser::GetAttributeIndex()
|
||||
{
|
||||
static Condenser::AttributeIndexSet attributeIndex(
|
||||
ELEMENTS(Condenser::AttributePointers),
|
||||
Condenser::AttributePointers,
|
||||
HeatSink::GetAttributeIndex()
|
||||
);
|
||||
return attributeIndex;
|
||||
}
|
||||
|
||||
Condenser::SharedData
|
||||
Condenser::DefaultData(
|
||||
Condenser::GetClassDerivations(),
|
||||
|
||||
Reference in New Issue
Block a user