P7: subsystem-tree alarm unification -- the whole PoweredSubsystem weapon/power subtree is byte-exact
The reconstruction modeled the binary's 0x54 AlarmIndicator (FUN_0041b9ec) with undersized
stand-ins (AlarmIndicator==ReconAlarm==4B; HeatAlarm==8B) across the entire subsystem tree, so
every field above an alarm sat at the wrong compiled offset. Retype every such stand-in to
GaugeAlarm54(0x54) and de-phantom each class against its ctor, so the whole PoweredSubsystem
subtree becomes byte-exact. An 8-agent read-only decomp-mapping workflow decoded every ctor
first; then hands-on implementation. static_assert-locked chain (verified vs the raw ctors):
HeatSink 0x1D0
-> PoweredSubsystem 0x31C retype electricalStateAlarm@0x264 + modeAlarm@0x2B8 @004b0f74
-> MechWeapon 0x3F0 retype weaponAlarm@0x350; delete 5 phantom tail fields @004b99a8
-> Emitter 0x478 delete outputVoltage/beamLengthRatio/firingArmed aliases
+ beamHit*/beamColor/beamHitData/energyRampTime phantoms;
retype beamOrientation EulerAngles->Quaternion(16B) @004bb120
-> PPC 0x478 (no own fields) @004bb888
PoweredSubsystem -> Sensor 0x328 (no alarm; 3 own fields) @004b1d18
PoweredSubsystem -> Myomers 0x358 (no alarm) @004b8fec
New systemic bug-class instances fixed (added to the CLAUDE.md checklist):
* alias field - Emitter outputVoltage==inherited rechargeLevel@0x320; beamLengthRatio==
beamScale.z@0x434; firingArmed==inherited useConfiguredPip@0x3E0
* phantom field - MechWeapon segmentReference/pipSegment/hasTarget/targetPoint/muzzlePoint
(past 0x3F0); Emitter beamHitPoint/beamImpact/beamImpactScalar/beamColor/
beamHitData/energyRampTime (binary writes inherited damageData/voltageScale
or the value is a method local)
Non-layout fixes required in the same wave:
* outputVoltage->rechargeLevel also in the compiled GAUSS.CPP:74/93 (external readers of the
removed Emitter field -- must grep EVERY TU, not just the class's own .cpp)
* MechWeapon::GetMuzzlePoint reimplemented faithfully (removed muzzlePoint collided with
Emitter's own fields at 0x3F0) via a BTResolveWeaponMuzzle void* bridge in mech4.cpp,
resolving the weapon's mount segment (inherited this+0xdc) through the owner segment table
* DetachFromVoltageSource fixed to set electricalStateAlarm not modeAlarm (raw @004b0e30
writes the 0x264 alarm)
The vehicleSubSystems aux-screen gauge raw reads (btl4gau2.cpp:868/952 at subsystem+0x2b8/+0x278)
and the Sensor RadarPercent path now read the CORRECT byte offsets (garbage under the short layout).
Verified: combat DESTROYED-in-8, 28 shots, 0 crashes, heat heatEnergy=1.34e7, every static_assert
lock passes, heapcheck-clean through construction (the phase the isolated PoweredSubsystem retype
had overflowed). LESSON: a factory-bridge runtime Check(sizeof<=alloc) does NOT fail the build --
only a static_assert sizeof lock catches alloc overflow at compile time.
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
1356870e56
commit
9d82be46a1
@@ -655,6 +655,29 @@ Scalar
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// BTResolveWeaponMuzzle -- the faithful FUN_004b9948 (MechWeapon::GetMuzzlePoint)
|
||||
// muzzle resolve: look up the weapon's mount segment (index, from the subsystem's
|
||||
// inherited this+0xdc slot) in the owner Mech's segment table and transform it to
|
||||
// world. Lives here (a complete-Mech TU with the segment API); mechweap.cpp treats
|
||||
// `owner` as a raw pointer so it calls this via a void* bridge instead of the Mech API.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
void
|
||||
BTResolveWeaponMuzzle(void *ownerMech, int segIndex, Point3D &out)
|
||||
{
|
||||
Mech *m = (Mech *)ownerMech;
|
||||
if (m == 0) { out = Point3D(0.0f, 0.0f, 0.0f); return; }
|
||||
EntitySegment *seg = m->GetSegment(segIndex); // owner+0x300 table, GetNth(index)
|
||||
if (seg != 0)
|
||||
{
|
||||
AffineMatrix mw;
|
||||
mw.Multiply(seg->GetSegmentToEntity(), m->localToWorld); // segment -> world (== mech4 gun-port path)
|
||||
out = mw; // Point3D = matrix W_Axis translation
|
||||
}
|
||||
else
|
||||
out = m->localOrigin.linearPosition; // safe non-garbage fallback (owner origin)
|
||||
}
|
||||
|
||||
void
|
||||
Mech::PerformAndWatch(const Time& till, MemoryStream *update_stream)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user