diff --git a/restoration/source410/BT/HEAT.CPP b/restoration/source410/BT/HEAT.CPP index 663a76cb..c469247a 100644 --- a/restoration/source410/BT/HEAT.CPP +++ b/restoration/source410/BT/HEAT.CPP @@ -880,7 +880,6 @@ Condenser::Condenser( // each condenser its share of the total valve opening. // valveState = 1; - condenserState = 0; // staged: bound by an authored watcher coolantFlowScale = 0.0f; refrigerationFactor = subsystem_resource->refrigerationFactor; massScale = refrigerationFactor; diff --git a/restoration/source410/BT/HEAT.HPP b/restoration/source410/BT/HEAT.HPP index f99a1415..90346017 100644 --- a/restoration/source410/BT/HEAT.HPP +++ b/restoration/source410/BT/HEAT.HPP @@ -511,7 +511,15 @@ // member goes at the END of the CLASS (never into the resource // struct above, which is a wire format). // - int condenserState; // authored watcher: CondenserN/CondenserState + // + // MUST BE A StateIndicator. The authored watcher for a *State + // name is an AudioStateWatcher, which is AudioWatcherOf + // and whose ctor immediately runs + // Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this) + // (AUDWTHR.CPP:891). Point it at a plain int and that call goes + // through garbage -- the pod dies on the extender. + // + StateIndicator condenserState; // authored watcher }; //########################################################################### diff --git a/restoration/source410/BT/POWERSUB.CPP b/restoration/source410/BT/POWERSUB.CPP index 6589d003..89957b12 100644 --- a/restoration/source410/BT/POWERSUB.CPP +++ b/restoration/source410/BT/POWERSUB.CPP @@ -596,7 +596,7 @@ const Generator::IndexEntry ATTRIBUTE_ENTRY(Generator, OutputVoltage, outputVoltage), ATTRIBUTE_ENTRY(Generator, RatedVoltage, ratedVoltage), ATTRIBUTE_ENTRY(Generator, GeneratorNumber, generatorNumber), - ATTRIBUTE_ENTRY(Generator, GeneratorState, generatorState) + ATTRIBUTE_ENTRY(Generator, GeneratorState, stateAlarm) }; Generator::AttributeIndexSet @@ -640,7 +640,6 @@ Generator::Generator( startTimer = startTime; stateAlarm.SetLevel(GeneratorReady); generatorOn = 1; - generatorState = 0; // staged shortRecoveryTime = subsystem_resource->shortRecoveryTime; shortTimer = shortRecoveryTime; diff --git a/restoration/source410/BT/POWERSUB.HPP b/restoration/source410/BT/POWERSUB.HPP index 3800db9f..c57293f8 100644 --- a/restoration/source410/BT/POWERSUB.HPP +++ b/restoration/source410/BT/POWERSUB.HPP @@ -479,7 +479,6 @@ Scalar shortRecoveryTime; Scalar shortTimer; AlarmIndicator stateAlarm; - int generatorState; // authored watcher: plain int, see RESERVR.HPP }; #endif diff --git a/restoration/source410/BT/RESERVR.CPP b/restoration/source410/BT/RESERVR.CPP index 57ada596..d57a826b 100644 --- a/restoration/source410/BT/RESERVR.CPP +++ b/restoration/source410/BT/RESERVR.CPP @@ -48,11 +48,24 @@ Reservoir::MessageHandlerSet HeatSink::MessageHandlers ); +const Reservoir::IndexEntry + Reservoir::AttributePointers[]= +{ + ATTRIBUTE_ENTRY(Reservoir, ReservoirState, reservoirAlarm) +}; + +Reservoir::AttributeIndexSet + Reservoir::AttributeIndex( + ELEMENTS(Reservoir::AttributePointers), + Reservoir::AttributePointers, + HeatSink::AttributeIndex + ); + Reservoir::SharedData Reservoir::DefaultData( Reservoir::ClassDerivations, Reservoir::MessageHandlers, - HeatSink::AttributeIndex, + Reservoir::AttributeIndex, Subsystem::StateCount ); diff --git a/restoration/source410/BT/RESERVR.HPP b/restoration/source410/BT/RESERVR.HPP index 1be0bf9b..6059be25 100644 --- a/restoration/source410/BT/RESERVR.HPP +++ b/restoration/source410/BT/RESERVR.HPP @@ -111,6 +111,15 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Local Data. The inject flag is the reservoir alarm's level (1 = flushing). // + public: + enum { + ReservoirStateAttributeID = HeatSink::NextAttributeID, + NextAttributeID + }; + + static const IndexEntry AttributePointers[]; + static AttributeIndexSet AttributeIndex; + protected: AlarmIndicator reservoirAlarm; Scalar coolantSquirtMass; diff --git a/restoration/source410/BT/TORSO.CPP b/restoration/source410/BT/TORSO.CPP index 7c730fb9..28b1298b 100644 --- a/restoration/source410/BT/TORSO.CPP +++ b/restoration/source410/BT/TORSO.CPP @@ -67,7 +67,6 @@ Torso::Torso( Check(owner); Check_Pointer(r); - motionState = 0; // staged: no gait state feed yet isDamagedCopy = (owner->GetInstance() == Entity::ReplicantInstance); statusFlags = 0; diff --git a/restoration/source410/BT/TORSO.HPP b/restoration/source410/BT/TORSO.HPP index 4cd15a96..645c3793 100644 --- a/restoration/source410/BT/TORSO.HPP +++ b/restoration/source410/BT/TORSO.HPP @@ -159,7 +159,15 @@ Scalar currentElevation; Scalar analogElevationAxis; Scalar analogTwistAxis; - int motionState; // staged: authored watcher Torso/MotionState + // + // MUST BE A StateIndicator. The authored watcher for a *State + // name is an AudioStateWatcher, which is AudioWatcherOf + // and whose ctor immediately runs + // Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this) + // (AUDWTHR.CPP:891). Point it at a plain int and that call goes + // through garbage -- the pod dies on the extender. + // + StateIndicator motionState; // authored watcher // // Twist/elevation dynamics accumulators advanced by TorsoSimulation. // Reserved until the per-frame sim is reconstructed (phase 5). diff --git a/restoration/source410/RENDER-ROADMAP.NOTES.md b/restoration/source410/RENDER-ROADMAP.NOTES.md index 199e400e..9166c571 100644 --- a/restoration/source410/RENDER-ROADMAP.NOTES.md +++ b/restoration/source410/RENDER-ROADMAP.NOTES.md @@ -354,6 +354,34 @@ the AttributeIndexSet::Build uninitialised-slot signature, so the next step is to dump Reservoir's built index set and compare it against a class whose publication works (Condenser is the control: same base, plain int, no crash). -STATE: Reservoir is REVERTED, the tree is green (clean Fail at ReservoirState, -no crash), and the ladder is blocked there until this is understood. Do not -"fix" it by publishing the name some other way without re-running the bisect. +SOLVED. The linker map named the faulting function outright: + + tlink32 -m writes build410/btl4opt.map; the crash address minus the CODE + base (0x410000) is the map offset, and "Publics by Value" gives the + enclosing symbol. 0x3B4AD landed inside + AudioStateWatcher::AudioStateWatcher(PlugStream*,Entity*) +0x2D. + +AudioStateWatcher is AudioWatcherOf and its ctor runs + + Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this) + (AUDWTHR.CPP:891) + +immediately. So every authored *State name MUST be published as a +StateIndicator (AlarmIndicator counts -- it derives from one). Point it at a +plain int and that member call goes through garbage and the pod dies on the +extender. That is why BOTH earlier attempts failed: the AlarmIndicator try +was right in type but was tested while other bugs were still in the batch, +and the "plain int" try was wrong in type and merely crashed further along. + +Fixed by publishing state objects: Reservoir/ReservoirState -> reservoirAlarm, +Generator/GeneratorState -> stateAlarm, and NEW StateIndicator members for +Condenser/CondenserState and Torso/MotionState. Note StateIndicator has no +Initialize() -- it takes its count in the ctor, and the default ctor is +enough here because the watcher only needs the object to exist (the socket it +attaches to is a member). Verified on the pod: no crash, ladder advanced to +ReportLeak. + +THE REUSABLE TECHNIQUE: when the pod dies with an extender fault, take the +address out of the dump, subtract 0x410000, and look it up in +btl4opt.map. It names the exact engine function -- which, for this family of +work, names the watcher class and therefore the required member type.