gauges: publish Mech attribute table (dense prefix 0x15..0x21 -> LinearSpeed live)
mech.cpp shipped an EMPTY, unchained Mech::AttributeIndex (a default-constructed AttributeIndexSet passed to DefaultData), so Simulation::GetAttributePointer severed the whole parent chain -> EVERY bare Mech gauge binding (LinearSpeed / MaxRunSpeed / DuckState / RadarRange / ...) resolved to NullAttribute. Add the Mech AttributeID enum (full binary set 0x15..0x38, VA 0x50be84) + a Mech::AttributePointers[] table + Mech::GetAttributeIndex() chained to JointedMover::GetAttributeIndex(), and change DefaultData to pass it. DENSE-TABLE HAZARD (systemic): AttributeIndexSet::Build (SIMULATE.cpp:565) sizes the built index to max(id) and Find (SIMULATE.cpp:663) strcmps EVERY slot, and Build does NOT zero gap slots -> an unpublished id between the parent's NextAttributeID and the max published id holds a garbage entryName -> AV on the next name lookup. So the table is a DENSE PREFIX 0x15..0x21 (JointedMover's NextAttributeID through LinearSpeed): the ids the BLH cockpit doesn't bind (collision/eyepoint/reticle/footstep/anim-state) point at one shared read-only attrPad member; CurrentSpeed/MaxRunSpeed bind to the existing gait members legCycleSpeed/reverseStrideLength; LinearSpeed binds a new linearSpeed member populated each frame in PerformAndWatch (|adv|/dt = forward ground speed). Ids 0x22..0x38 stay declared in the enum for later extension (RadarRange/DuckState when the map/duck widgets land) but are NOT published yet. New members appended to Mech's own region (no locked base/gait offset shifts); inited in the ctor. Verified live (BT_DEV_GAUGES + drive): the radar-surface SPEED readout (numericSpeed(LinearSpeed), a base engine primitive already drawing NULL) now shows 225 (~63 u/s in the widget's display units) instead of 0, tracking the mech's motion. Heat surface CurrentTemperature=77 un-regressed. Combat un- regressed (TARGET DESTROYED after 8 hits), 0 attribute-not-found, and Mech construction + attribute-index build is heap-clean under BT_HEAPCHECK. 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
9ea4bdaf50
commit
9e31408ba2
@@ -399,14 +399,52 @@ Derivation
|
||||
Receiver::MessageHandlerSet
|
||||
Mech::MessageHandlers(Entity::GetMessageHandlers());
|
||||
|
||||
Mech::AttributeIndexSet
|
||||
Mech::AttributeIndex;
|
||||
//
|
||||
// Mech attribute table. DENSE PREFIX 0x15..0x21 (JointedMover::NextAttributeID
|
||||
// through LinearSpeed): the built index is a dense array and Find strcmps every
|
||||
// slot, so the table must be contiguous from the parent's NextAttributeID up to
|
||||
// the highest id published -- no gaps. The ids the BLH cockpit does not consume
|
||||
// (collision/eyepoint/reticle/footstep/anim state) bind to the shared read-only
|
||||
// attrPad so the slot is a valid, named, non-crashing entry; CurrentSpeed and
|
||||
// MaxRunSpeed bind to the existing gait members; LinearSpeed binds to the live
|
||||
// forward-speed member the speed gauges read. (Ids 0x22..0x38 remain declared in
|
||||
// the enum for later extension -- e.g. RadarRange/DuckState when the map/duck
|
||||
// widgets are reconstructed -- but are NOT published yet.)
|
||||
//
|
||||
const Mech::IndexEntry
|
||||
Mech::AttributePointers[]=
|
||||
{
|
||||
ATTRIBUTE_ENTRY(Mech, MaxAcceleration, attrPad), // 0x15
|
||||
ATTRIBUTE_ENTRY(Mech, CollisionState, attrPad), // 0x16
|
||||
ATTRIBUTE_ENTRY(Mech, CollisionNormal, attrPad), // 0x17
|
||||
ATTRIBUTE_ENTRY(Mech, CollisionSpeed, attrPad), // 0x18
|
||||
ATTRIBUTE_ENTRY(Mech, CollisionMaterialType, attrPad), // 0x19
|
||||
ATTRIBUTE_ENTRY(Mech, CurrentSpeed, legCycleSpeed), // 0x1a (existing @0x348)
|
||||
ATTRIBUTE_ENTRY(Mech, MaxRunSpeed, reverseStrideLength), // 0x1b (existing @0x34c = run/top speed)
|
||||
ATTRIBUTE_ENTRY(Mech, EyepointRotation, attrPad), // 0x1c
|
||||
ATTRIBUTE_ENTRY(Mech, TargetReticle, attrPad), // 0x1d
|
||||
ATTRIBUTE_ENTRY(Mech, FootStep, attrPad), // 0x1e
|
||||
ATTRIBUTE_ENTRY(Mech, AnimationState, attrPad), // 0x1f
|
||||
ATTRIBUTE_ENTRY(Mech, ReplicantAnimationState, attrPad), // 0x20
|
||||
ATTRIBUTE_ENTRY(Mech, LinearSpeed, linearSpeed) // 0x21 (live forward speed)
|
||||
};
|
||||
|
||||
Mech::AttributeIndexSet&
|
||||
Mech::GetAttributeIndex()
|
||||
{
|
||||
static Mech::AttributeIndexSet attributeIndex(
|
||||
ELEMENTS(Mech::AttributePointers),
|
||||
Mech::AttributePointers,
|
||||
JointedMover::GetAttributeIndex()
|
||||
);
|
||||
return attributeIndex;
|
||||
}
|
||||
|
||||
Mech::SharedData
|
||||
Mech::DefaultData( // @0050bde4
|
||||
&Mech::ClassDerivations,
|
||||
Mech::MessageHandlers,
|
||||
Mech::AttributeIndex,
|
||||
Mech::GetAttributeIndex(),
|
||||
Mech::StateCount,
|
||||
(Entity::MakeHandler)Mech::Make // Entity__SharedData adds the make-callback
|
||||
);
|
||||
@@ -532,6 +570,8 @@ Mech::Mech(
|
||||
hudSubsystem = 0; // this[0x16d] (0xBD6 -> HUD; was misnamed mechTechSubsystem)
|
||||
forwardThrottleScale = 1.0f; // @0x5c0 mapper speed scale (writer not in decomp; neutral)
|
||||
sensorSubsystem = 0; // this[0x1f7] (0xBBE) -- same hazard, zero it too
|
||||
attrPad = 0.0f; // shared read pad for un-populated gauge attributes
|
||||
linearSpeed = 0.0f; // live forward ground speed (LinearSpeed gauge); set per frame
|
||||
|
||||
ZeroBlock(this + 0xca, 6); // this[0xca..0xcf] = 0
|
||||
ZeroBlock(this + 0x153, 6); // this[0x153..0x158] = 0
|
||||
|
||||
@@ -503,9 +503,72 @@ protected:
|
||||
//
|
||||
public:
|
||||
static Receiver::MessageHandlerSet MessageHandlers; // SharedData ctor operand
|
||||
static AttributeIndexSet AttributeIndex; // SharedData ctor operand
|
||||
enum { StateCount = 0x21 };
|
||||
|
||||
//
|
||||
// Attribute Support -- the named attributes the cockpit gauges bind to.
|
||||
// The config (content/GAUGE/L4GAUGE.CFG) binds the bare names LinearSpeed /
|
||||
// MaxRunSpeed / DuckState / RadarRange / RadarLinearPosition /
|
||||
// RadarAngularPosition, resolved by Simulation::GetAttributePointer ->
|
||||
// activeAttributeIndex->Find(name). The reconstruction shipped an EMPTY,
|
||||
// unchained Mech::AttributeIndex, so EVERY bare Mech gauge (and even the
|
||||
// inherited attributes) resolved to NullAttribute.
|
||||
//
|
||||
// The full binary id set (0x15..0x38, table VA 0x50be84) is declared so the
|
||||
// published table can be extended without renumbering. The chain starts at
|
||||
// JointedMover::NextAttributeID (0x15); ids MUST stay contiguous, because the
|
||||
// built index is a dense array sized to max(id) and AttributeIndexSet::Find
|
||||
// strcmps EVERY slot -- an unfilled slot holds a garbage entryName -> AV.
|
||||
//
|
||||
enum {
|
||||
MaxAccelerationAttributeID = JointedMover::NextAttributeID, // 0x15
|
||||
CollisionStateAttributeID, // 0x16
|
||||
CollisionNormalAttributeID, // 0x17
|
||||
CollisionSpeedAttributeID, // 0x18
|
||||
CollisionMaterialTypeAttributeID, // 0x19
|
||||
CurrentSpeedAttributeID, // 0x1a
|
||||
MaxRunSpeedAttributeID, // 0x1b
|
||||
EyepointRotationAttributeID, // 0x1c
|
||||
TargetReticleAttributeID, // 0x1d
|
||||
FootStepAttributeID, // 0x1e
|
||||
AnimationStateAttributeID, // 0x1f
|
||||
ReplicantAnimationStateAttributeID, // 0x20
|
||||
LinearSpeedAttributeID, // 0x21
|
||||
ClimbRateAttributeID, // 0x22
|
||||
AccelerationLastFrameAttributeID, // 0x23
|
||||
AngularSpeedAttributeID, // 0x24
|
||||
ArmorDamageLevelAttributeID, // 0x25
|
||||
SubsystemDamageLevelAttributeID, // 0x26
|
||||
MyomerDamageLevelAttributeID, // 0x27
|
||||
TestButton1AttributeID, // 0x28
|
||||
TestButton2AttributeID, // 0x29
|
||||
TestButton3AttributeID, // 0x2a
|
||||
TestButton4AttributeID, // 0x2b
|
||||
TestButton5AttributeID, // 0x2c
|
||||
TestButton6AttributeID, // 0x2d
|
||||
ReduceButtonAttributeID, // 0x2e
|
||||
RadarRangeAttributeID, // 0x2f
|
||||
RadarLinearPositionAttributeID, // 0x30
|
||||
RadarAngularPositionAttributeID, // 0x31
|
||||
RearFiringAttributeID, // 0x32
|
||||
RequestDuckAnimationAttributeID, // 0x33
|
||||
UnstablePercentageAttributeID, // 0x34
|
||||
SuperStopAttributeID, // 0x35
|
||||
IncomingLockAttributeID, // 0x36
|
||||
DuckStateAttributeID, // 0x37
|
||||
DistanceToMissileAttributeID, // 0x38
|
||||
NextAttributeID // 0x39
|
||||
};
|
||||
static const IndexEntry AttributePointers[];
|
||||
static AttributeIndexSet& GetAttributeIndex();
|
||||
|
||||
// Cockpit-gauge attribute backing members (APPENDED to Mech's own region --
|
||||
// never at a locked base/gait offset). attrPad is a shared read-only 0 for
|
||||
// the dense-prefix ids the BLH cockpit does not bind; linearSpeed is the live
|
||||
// forward ground speed the speed readout / arc / radar consume (binary @0x81c).
|
||||
Scalar attrPad;
|
||||
Scalar linearSpeed;
|
||||
|
||||
// --- raw / engine-shim members touched by the ctor slice -------------
|
||||
void *vtable; // installed Mech vtable ptr
|
||||
Word instanceFlags; // entity instance flags (this+0x18 region)
|
||||
|
||||
@@ -1290,6 +1290,7 @@ void
|
||||
// leg channel keeps running as the local sim it is in the binary
|
||||
// (its joint writes land first and are overwritten by the body's).
|
||||
const Scalar localAdv = adv * dir;
|
||||
linearSpeed = (localAdv < 0.0f ? -localAdv : localAdv) * invDt; // forward ground speed -> LinearSpeed gauge
|
||||
Vector3D localVel(0.0f, 0.0f, -localAdv * invDt); // exact frame distance as velocity
|
||||
Matrix34 orient; // rotation from the heading (set @ line ~626)
|
||||
Matrix34::FromQuaternion(&orient, &localOrigin.angularPosition);
|
||||
@@ -1348,6 +1349,7 @@ void
|
||||
: ((throttle < 0.0f) ? -1.0f : 1.0f);
|
||||
localOrigin.linearPosition.x += fx * adv * dir;
|
||||
localOrigin.linearPosition.z += fz * adv * dir;
|
||||
linearSpeed = (dt > 0.0f) ? ((adv < 0.0f ? -adv : adv) / dt) : 0.0f; // LinearSpeed gauge
|
||||
localToWorld = localOrigin; // rebuild with the new position
|
||||
|
||||
gBodyAnimLog += dt;
|
||||
|
||||
Reference in New Issue
Block a user