From 3ecd88aaef91a02383b6643d7c4fd5e09c42d359 Mon Sep 17 00:00:00 2001 From: Cyd Date: Tue, 28 Jul 2026 01:25:40 -0500 Subject: [PATCH] BT410 5.3.44: read the whole watcher list out of the resource; Torso MotionState BTL4.RES stores each watcher as a (SUBSYSTEM, ATTRIBUTE) string pair, so the complete list can be extracted directly instead of discovering one name per 6-minute run. Banked the extraction method and the full normalised table. Sixth rung climbed: Torso/MotionState (staged member, appended at the end of Torso's own range so no downstream id moves). LocalVelocity and LocalAcceleration turn out to need nothing -- the engine's Mover already publishes them. Also banked, and deliberately NOT acted on: ReportLeak and ConfigureActivePress are base-class attributes inside the pinned range, and chasing them turned up what looks like the authentic attribute layout. The shipped pool gives MechSubsystem 1, HeatableSubsystem 3, HeatSink 6, PoweredSubsystem 5 -- which counted from Subsystem::NextAttributeID=2 lands MechWeapon's real ids on the binary-pinned 0x12 with EXACTLY ONE pad, where our tree needs three. That arithmetic is strong evidence for the original layout, and reconciling to it would replace three guessed pads with the real table. But it moves ids underneath a cockpit currently verified at 98.9% pixel-identical, so it wants a deliberate session with the A/B rig open rather than a bulk edit at the end of a long one. Co-Authored-By: Claude Fable 5 --- restoration/source410/BT/TORSO.CPP | 4 +- restoration/source410/BT/TORSO.HPP | 7 ++ restoration/source410/RENDER-ROADMAP.NOTES.md | 77 +++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/restoration/source410/BT/TORSO.CPP b/restoration/source410/BT/TORSO.CPP index 0cf43829..7c730fb9 100644 --- a/restoration/source410/BT/TORSO.CPP +++ b/restoration/source410/BT/TORSO.CPP @@ -37,7 +37,8 @@ const Torso::IndexEntry ATTRIBUTE_ENTRY(Torso, HorizontalLimitRight, horizontalLimitRight), ATTRIBUTE_ENTRY(Torso, HorizontalLimitLeft, horizontalLimitLeft), ATTRIBUTE_ENTRY(Torso, SpeedOfTorsoVertical, baseElevationRate), - ATTRIBUTE_ENTRY(Torso, SpeedOfTorsoHorizontal, baseTwistRate) + ATTRIBUTE_ENTRY(Torso, SpeedOfTorsoHorizontal, baseTwistRate), + ATTRIBUTE_ENTRY(Torso, MotionState, motionState) }; Torso::AttributeIndexSet @@ -66,6 +67,7 @@ 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 8a9bd710..6a847199 100644 --- a/restoration/source410/BT/TORSO.HPP +++ b/restoration/source410/BT/TORSO.HPP @@ -123,6 +123,12 @@ HorizontalLimitLeftAttributeID, SpeedOfTorsoVerticalAttributeID, SpeedOfTorsoHorizontalAttributeID, + // + // Bound by an authored watcher (BTL4.RES pairs it as + // Torso/MotionState). Appended at the END of this leaf class's + // own range, so no downstream id moves. + // + MotionStateAttributeID, NextAttributeID }; @@ -130,6 +136,7 @@ static AttributeIndexSet AttributeIndex; protected: + int motionState; // staged: no gait state feed yet int isDamagedCopy; int statusFlags; Logical horizontalEnabled; diff --git a/restoration/source410/RENDER-ROADMAP.NOTES.md b/restoration/source410/RENDER-ROADMAP.NOTES.md index 01a0a5d8..bf6310c0 100644 --- a/restoration/source410/RENDER-ROADMAP.NOTES.md +++ b/restoration/source410/RENDER-ROADMAP.NOTES.md @@ -239,3 +239,80 @@ TYPES ARE PROVISIONAL on the staged members. AttributeWatcherOf reads *(T*)attributePointer (WATCHER.HPP:288) and the instantiation comes from the resource, which the string pool does not reveal. Nothing drives these yet so no watcher can fire -- settle the types WITH the models that write them. + +-------------------------------------------------------------------------------- +THE WATCHER LIST IS NOW FULLY KNOWN -- stop discovering it one run at a time +-------------------------------------------------------------------------------- +BTL4.RES stores each watcher as a (SUBSYSTEM, ATTRIBUTE) string pair, so the +whole list can be read straight out of the resource instead of one 6-minute +run per name: + + for each candidate name, find its NUL-terminated occurrences in BTL4.RES + and take the printable string immediately before it -- that is the owning + subsystem. Candidates = strings present in BOTH BTL4.RES and BTL4OPT.EXE + matching ^[A-Z][A-Za-z0-9]{3,}$ (59 of them). + +Normalised across instance names (ERMLaser_1/2/3 -> the weapon class, +AmmoBinSRM6_1 -> AmmoBin, Condenser1..6 -> Condenser, GeneratorA..D -> +Generator), the COMPLETE set the engine will demand is: + + Entity AnimationState(306) LocalVelocity(324) SimulationState(74) + CollisionSpeed(72) CollisionState(54) FootStep(36) + IncomingLock(36) UnstablePercentage(36) LocalAcceleration(18) + DistanceToMissile(18) ReduceButton(18) CollisionNormal(18) + weapons WeaponState PercentDone LaserOn ReportLeak + ConfigureActivePress SimulationState + AmmoBin AmmoState FireCountdownStarted SimulationState + Condenser CondenserState ReportLeak + Generator GeneratorOn GeneratorState ReportLeak + Reservoir ReservoirState + Myomers SpeedEffect ConfigureActivePress ReportLeak SimulationState + Avionics(Sensor) ConfigureActivePress ReportLeak SimulationState + ControlsMapper DisplayMode Look{Forward,Left,Right,Down,Behind} + TargetRangeExponent + Torso SpeedOfTorsoHorizontal MotionState + HeatSink CurrentTemperature + +DONE so far (6 rungs, each run-verified): UnstablePercentage, SpeedEffect, +AnimationState, CollisionState/Normal, ReduceButton, SpeedOfTorsoHorizontal +(+ the whole Torso table), MotionState. LocalVelocity / LocalAcceleration +need nothing -- the ENGINE's Mover already publishes them (MOVER.CPP:104). + +LEAF-SAFE APPENDS (do these next; each goes at the END of a class that +nothing chains off, so no id moves): ReservoirState, CondenserState, +GeneratorState (maps to the EXISTING stateAlarm), AmmoState + +FireCountdownStarted (AmmoBin has no table at all yet), LaserOn (Emitter), +TargetRangeExponent (ControlsMapper). + +-------------------------------------------------------------------------------- +!! ReportLeak AND ConfigureActivePress ARE NOT LEAF-SAFE -- and they reveal + the authentic attribute layout. DO NOT bulk-edit these without deciding. +-------------------------------------------------------------------------------- +Both belong to BASE classes in the pinned range. The shipped string pool +gives each class's attribute names contiguously in id order: + + MechSubsystem ConfigureActivePress (1) + HeatableSubsystem CurrentTemperature DegradationTemperature + FailureTemperature (3) + HeatSink NormalizedPressure DegradationPressure + CoolantCapacity CoolantMass + CoolantMassLeakRate ReportLeak (6) + PoweredSubsystem InputVoltage AuxScreenNumber AuxScreenPlacement + AuxScreenLabel EngScreenLabel (5) + +Count them from Subsystem::NextAttributeID = 2: 2 | 3..5 | 6..0x0B | +0x0C..0x10 -> NextAttributeID = 0x11 -> MechWeapon needs EXACTLY ONE pad +to land its real ids on the binary-pinned 0x12. Our tree needs THREE pads, +because our tables differ: we publish HeatLoad (authentic does not), +CoolantAvailable (authentic does not), and a different PoweredSubsystem five +(OutputVoltage/RatedVoltage/VoltageState/ConnectMode instead of the four +AuxScreen* names). The one-pad arithmetic landing exactly on 0x12 is strong +evidence the four rows above ARE the original layout. + +Reconciling to it is a real improvement -- it would replace three guessed +pads with the authentic table -- but it moves ids underneath the gauge +cockpit that is currently verified at 98.9% pixel-identical, so it wants a +deliberate session with the A/B rig open, not a bulk edit at the end of a +long one. Neither HeatLoad nor CoolantAvailable is bound by any gauge (0 +hits in L4GAUGE.CFG), so the drop side looks cheap; the risk is the id shift, +not the names.