Gyro tail + audio (task #66): the INSTABILITY MODEL -- mech+0x3F0 reconstructed
Byte-decoded the un-exported master-perf block @0x4aad3d-0x4aaf14 (capstone;
the same gap that held the F5 footstep code) [T1]:
instab = (min(|AccelerationLastFrame| / maxUnstableAcceleration, 1)
x unstableAccelerationEffect)^2
instab += clamp((demand - legCycleSpeed)/demand, <=1) # "gun the engine"
x unstableGunTheEngineEffect # (demand clamped to
# [gimpStride(neg), runMax2])
if (legAnimationState == 4 /*turn-in-place*/) instab += unstableStopedTurnEffect
clamp to 1 -> mech+0x3F0 -> gyro->swayBias (gyro+0x3A8)
Every piece resolves to already-reconstructed structure: the model-record
tuning block rec+0x80..0x94 (ctor copy @0x4a2593 -- the six authored
Unstable* fields, previously parked in the Wword scratch bank, now real
members); AccelerationLastFrame@0x82c = the snapshot of the ring-derived
localAcceleration (copied at the perf tail @0x4ab142); CurrentSpeed@0x348 =
legCycleSpeed; the trn state 4 gate; and the gyro feed lands in the
EXISTING swayBias member + GyroscopeSimulation consumer (task #56) --
GyroFrameJointWrite's "0.0f model TBD" argument is now the live value.
UnstablePercentage (binary id 52 @0x3F0) binds the real member: the LAST
dead audio attribute is live -- the authored instability alarm (start
thresh 0.01 + volume = the fraction) sounds under hard maneuvers, and the
cockpit ambient sway now scales with reckless driving.
Live verification (30s, 0.6-throttle run): instab 0.38 during the walk->run
chase (cyc 22.2 vs demand 33.6), settling to 0.002-0.12 per-stride ripple at
steady run; attribute binds with live float values; [instab] trace under
BT_GYRO_TRACE. unstableSuperStopEffect/unstableHighVelocityEffect writers
remain unlocated (plausibly the airborne perf variant) -- noted on members.
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
c581553a6c
commit
c51d64a6b8
@@ -5,7 +5,7 @@ status: living
|
|||||||
source_sections: "task #55 (2026-07-10); reference/decomp part_007.c/part_013.c/part_014.c/part_011.c; engine/MUNGA_L4/bgfload.cpp, L4VIDRND.cpp; game/reconstructed/btl4vid.cpp"
|
source_sections: "task #55 (2026-07-10); reference/decomp part_007.c/part_013.c/part_014.c/part_011.c; engine/MUNGA_L4/bgfload.cpp, L4VIDRND.cpp; game/reconstructed/btl4vid.cpp"
|
||||||
related_topics: [rendering, bgf-format, gauges-hud, subsystems, decomp-reference]
|
related_topics: [rendering, bgf-format, gauges-hud, subsystems, decomp-reference]
|
||||||
key_terms: [material-ramp, siteeyepoint]
|
key_terms: [material-ramp, siteeyepoint]
|
||||||
open_questions: ["gyro tail: gait jolt/rumble [T3 gates], sway model, torso-pitch eye writer, damageForce fill", "exact authored frame colour: the unlit constant (0.13,0.12,0.15) is T3 tuned-to-footage (BT_COP_FRAME overrides; the ramp-index approach + BT_COP_RAMP_L are RETIRED)"]
|
open_questions: ["gyro tail: gait jolt/rumble [T3 gates], torso-pitch eye writer, damageForce fill (sway model DONE: the mech instability model @0x3F0 feeds swayBias -- task #66)", "exact authored frame colour: the unlit constant (0.13,0.12,0.15) is T3 tuned-to-footage (BT_COP_FRAME overrides; the ramp-index approach + BT_COP_RAMP_L are RETIRED)"]
|
||||||
---
|
---
|
||||||
# First-Person Cockpit: the *_cop Canopy + the Authentic Eyepoint
|
# First-Person Cockpit: the *_cop Canopy + the Authentic Eyepoint
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
> **STATUS (2026-07-16): Phases 1-4 SHIPPED** (commits fc7f311, 691e885, 0ca7d26,
|
> **STATUS (2026-07-16): Phases 1-4 SHIPPED** (commits fc7f311, 691e885, 0ca7d26,
|
||||||
> cc2b109..0e2401f). Fixed: F1-F5, F7, F9-F13, F15, F16, F18-F20, F23, KB items;
|
> cc2b109..0e2401f). Fixed: F1-F5, F7, F9-F13, F15, F16, F18-F20, F23, KB items;
|
||||||
> F6 fixed (ReportLeak -> coolantActive@0x138, binary table [T1]); F14 partial
|
> F6 fixed (ReportLeak -> coolantActive@0x138, binary table [T1]); F14 partial
|
||||||
> (attenuation baked; static fc/Q deferred); F17 partial (CollisionSpeed +
|
> (attenuation baked; static fc/Q deferred); F17 FIXED (CollisionSpeed +
|
||||||
> ReduceButton real; UnstablePercentage deferred on the gyro sway model);
|
> ReduceButton real; UnstablePercentage live -- the instability model @0x3F0 is
|
||||||
|
> byte-decoded and reconstructed, task #66);
|
||||||
> F8/F21/F22 open (voice budget unhit / attack polish / HRTF option).
|
> F8/F21/F22 open (voice budget unhit / attack polish / HRTF option).
|
||||||
> attrnull = 0: every authored audio attribute binds a real member.
|
> attrnull = 0: every authored audio attribute binds a real member.
|
||||||
|
|
||||||
|
|||||||
@@ -733,7 +733,7 @@ const Mech::IndexEntry
|
|||||||
ATTRIBUTE_ENTRY(Mech, RadarAngularPosition, radarAngularPosition),// 0x31 (Quaternion* -> localOrigin)
|
ATTRIBUTE_ENTRY(Mech, RadarAngularPosition, radarAngularPosition),// 0x31 (Quaternion* -> localOrigin)
|
||||||
ATTRIBUTE_ENTRY(Mech, RearFiring, attrPad), // 0x32
|
ATTRIBUTE_ENTRY(Mech, RearFiring, attrPad), // 0x32
|
||||||
ATTRIBUTE_ENTRY(Mech, RequestDuckAnimation, attrPad), // 0x33
|
ATTRIBUTE_ENTRY(Mech, RequestDuckAnimation, attrPad), // 0x33
|
||||||
ATTRIBUTE_ENTRY(Mech, UnstablePercentage, attrPad), // 0x34
|
ATTRIBUTE_ENTRY(Mech, UnstablePercentage, unstablePercentage), // 0x34 (task #66: the instability alarm; binary id 52 @0x3F0)
|
||||||
ATTRIBUTE_ENTRY(Mech, SuperStop, attrPad), // 0x35
|
ATTRIBUTE_ENTRY(Mech, SuperStop, attrPad), // 0x35
|
||||||
// (AUDIO_FIDELITY F7) real missile-alarm backing: binary ids 54/56 @0x3fc/
|
// (AUDIO_FIDELITY F7) real missile-alarm backing: binary ids 54/56 @0x3fc/
|
||||||
// 0x400 [T1 table @0x50c0b0/0x50c0d0]; the authored beeper (match 1/0) +
|
// 0x400 [T1 table @0x50c0b0/0x50c0d0]; the authored beeper (match 1/0) +
|
||||||
@@ -939,6 +939,9 @@ Mech::Mech(
|
|||||||
accelPrevFwdMean = 0.0f;
|
accelPrevFwdMean = 0.0f;
|
||||||
accelPrevVertMean = 0.0f;
|
accelPrevVertMean = 0.0f;
|
||||||
accelPrevPos = localOrigin.linearPosition;
|
accelPrevPos = localOrigin.linearPosition;
|
||||||
|
// (task #66) instability accumulator: the binary reset zeroes 0x3F0
|
||||||
|
// (part_012.c:9420); the tuning members are set from the model record below.
|
||||||
|
unstablePercentage = 0.0f;
|
||||||
fwdSpeedFiltered = 0.0f; // smoothed published velocity (see mech4 derive)
|
fwdSpeedFiltered = 0.0f; // smoothed published velocity (see mech4 derive)
|
||||||
vertSpeedFiltered = 0.0f;
|
vertSpeedFiltered = 0.0f;
|
||||||
{ extern void *g_btFootStepAddr; g_btFootStepAddr = &footStep; } // DIAG: watcher-poll tracer target
|
{ extern void *g_btFootStepAddr; g_btFootStepAddr = &footStep; } // DIAG: watcher-poll tracer target
|
||||||
@@ -1391,12 +1394,14 @@ Mech::Mech(
|
|||||||
<< " superStop=" << airborneCycleRate
|
<< " superStop=" << airborneCycleRate
|
||||||
<< " throttleAdj=" << forwardThrottleScale << std::endl;
|
<< " throttleAdj=" << forwardThrottleScale << std::endl;
|
||||||
Wword(0x12f) = model->relativeMechValue; // rec+0x70 -> mech+0x4bc
|
Wword(0x12f) = model->relativeMechValue; // rec+0x70 -> mech+0x4bc
|
||||||
Wword(0x1e1) = model->maxUnstableAcceleration; // rec+0x80-0x94 -> mech+0x784..0x798
|
// (task #66) the six Unstable* tuning fields are REAL members now (the
|
||||||
Wword(0x1e2) = model->unstableAccelerationEffect; // (the six Unstable* effects)
|
// instability model consumes them); binary rec+0x80-0x94 -> mech+0x784..0x798.
|
||||||
Wword(0x1e3) = model->unstableGunTheEngineEffect;
|
maxUnstableAcceleration = model->maxUnstableAcceleration;
|
||||||
Wword(0x1e4) = model->unstableSuperStopEffect;
|
unstableAccelerationEffect = model->unstableAccelerationEffect;
|
||||||
Wword(0x1e5) = model->unstableHighVelocityEffect;
|
unstableGunTheEngineEffect = model->unstableGunTheEngineEffect;
|
||||||
Wword(0x1e6) = model->unstableStopedTurnEffect;
|
unstableSuperStopEffect = model->unstableSuperStopEffect;
|
||||||
|
unstableHighVelocityEffect = model->unstableHighVelocityEffect;
|
||||||
|
unstableStopedTurnEffect = model->unstableStopedTurnEffect;
|
||||||
|
|
||||||
// Angle fields converted from degrees to radians.
|
// Angle fields converted from degrees to radians.
|
||||||
Wword(0x159) = (int)(model->lookLeftAngle * DegreesToRadians); // +0x50
|
Wword(0x159) = (int)(model->lookLeftAngle * DegreesToRadians); // +0x50
|
||||||
|
|||||||
@@ -879,6 +879,25 @@ protected:
|
|||||||
Scalar accelPrevFwdMean;
|
Scalar accelPrevFwdMean;
|
||||||
Scalar accelPrevVertMean;
|
Scalar accelPrevVertMean;
|
||||||
Point3D accelPrevPos; // raw position memory for the ring feed
|
Point3D accelPrevPos; // raw position memory for the ring feed
|
||||||
|
// (task #66, the gyro-tail INSTABILITY MODEL -- byte-decoded from the
|
||||||
|
// master perf @0x4aad3d-0x4aaf14 [T1]):
|
||||||
|
// instab = (min(|AccelerationLastFrame| / maxUnstableAcceleration, 1)
|
||||||
|
// x unstableAccelerationEffect)^2
|
||||||
|
// instab += clamp((demand - legCycleSpeed)/demand, <=1) ["gun the
|
||||||
|
// engine": commanded speed the legs haven't reached]
|
||||||
|
// x unstableGunTheEngineEffect
|
||||||
|
// if (legAnimationState == 4 /*trn*/) instab += unstableStopedTurnEffect
|
||||||
|
// clamp to 1 -> mech+0x3F0, then gyro->swayBias (gyro+0x3A8) and the
|
||||||
|
// UnstablePercentage audio attribute (binary id 52 @0x3F0) read it.
|
||||||
|
// The six tuning fields come from the model record +0x80..0x94 (ctor
|
||||||
|
// @0x4a2593-0x4a25d5); previously parked in the Wword scratch bank.
|
||||||
|
Scalar unstablePercentage; // binary @0x3F0 (reset writes 0)
|
||||||
|
Scalar maxUnstableAcceleration; // @0x784 <- rec+0x80
|
||||||
|
Scalar unstableAccelerationEffect; // @0x788 <- rec+0x84
|
||||||
|
Scalar unstableGunTheEngineEffect; // @0x78C <- rec+0x88
|
||||||
|
Scalar unstableSuperStopEffect; // @0x790 <- rec+0x8C (writer not yet located; airborne perf?)
|
||||||
|
Scalar unstableHighVelocityEffect; // @0x794 <- rec+0x90 (writer not yet located)
|
||||||
|
Scalar unstableStopedTurnEffect; // @0x798 <- rec+0x94
|
||||||
// Radar/map gauge attributes (binary @0x404/0x408/0x40c/0x3f8). The map
|
// Radar/map gauge attributes (binary @0x404/0x408/0x40c/0x3f8). The map
|
||||||
// widget reads position/angle as POINTERS into the mech's live origin, so
|
// widget reads position/angle as POINTERS into the mech's live origin, so
|
||||||
// radarLinearPosition/radarAngularPosition point at localOrigin.{linear,
|
// radarLinearPosition/radarAngularPosition point at localOrigin.{linear,
|
||||||
|
|||||||
@@ -5244,13 +5244,54 @@ void
|
|||||||
//
|
//
|
||||||
if (GetInstance() == MasterInstance)
|
if (GetInstance() == MasterInstance)
|
||||||
{
|
{
|
||||||
|
// (task #66) INSTABILITY MODEL -- byte-decoded from the binary master
|
||||||
|
// perf @0x4aad3d-0x4aaf14 [T1] (the un-exported gap; capstone disasm).
|
||||||
|
// Runs HERE, right before the gyro dispatch, exactly as the binary
|
||||||
|
// does: it reads LAST frame's acceleration snapshot (the tail updates
|
||||||
|
// localAcceleration afterwards -- "AccelerationLastFrame", the same
|
||||||
|
// vector the binary copies to +0x82c after this point).
|
||||||
|
{
|
||||||
|
// term 1: acceleration sway, squared
|
||||||
|
Scalar a = localAcceleration.linearMotion.Length();
|
||||||
|
a = (maxUnstableAcceleration > 0.0f) ? a / maxUnstableAcceleration : 0.0f;
|
||||||
|
if (a > 1.0f) a = 1.0f;
|
||||||
|
a *= unstableAccelerationEffect;
|
||||||
|
unstablePercentage = a * a;
|
||||||
|
// term 2: "gun the engine" -- commanded speed the legs haven't
|
||||||
|
// reached, as a fraction of the command (negative when coasting
|
||||||
|
// past the demand -- the binary does not floor it)
|
||||||
|
MechControlsMapper *im = MappingMapper();
|
||||||
|
Scalar u = (im != 0) ? im->speedDemand : 0.0f;
|
||||||
|
if (u > reverseSpeedMax2) u = reverseSpeedMax2; // @0x7a0 run cap
|
||||||
|
if (u < gimpStrideLength) u = gimpStrideLength; // @0x350 (negative reverse cap)
|
||||||
|
Scalar r = 0.0f;
|
||||||
|
if (u > 0.0f)
|
||||||
|
r = (u - legCycleSpeed) / u;
|
||||||
|
else if (u < 0.0f)
|
||||||
|
{
|
||||||
|
r = u - legCycleSpeed;
|
||||||
|
r = ((r <= 0.0f) ? -r : r) / (-u);
|
||||||
|
}
|
||||||
|
if (r > 1.0f) r = 1.0f;
|
||||||
|
unstablePercentage += r * unstableGunTheEngineEffect;
|
||||||
|
// term 3: turning in place (trn, leg state 4)
|
||||||
|
if (legAnimationState == 4)
|
||||||
|
unstablePercentage += unstableStopedTurnEffect;
|
||||||
|
if (unstablePercentage > 1.0f) unstablePercentage = 1.0f;
|
||||||
|
if (getenv("BT_GYRO_TRACE")) { static long s_it=0; if ((++s_it % 120)==0)
|
||||||
|
DEBUG_STREAM << "[instab] " << unstablePercentage
|
||||||
|
<< " (|a|=" << localAcceleration.linearMotion.Length()
|
||||||
|
<< " demand=" << u << " cyc=" << legCycleSpeed
|
||||||
|
<< " legState=" << legAnimationState << ")\n" << std::flush; }
|
||||||
|
}
|
||||||
|
|
||||||
extern void GyroFrameJointWrite(Subsystem *, Scalar, int, int);
|
extern void GyroFrameJointWrite(Subsystem *, Scalar, int, int);
|
||||||
static int s_gyrodbg = 0;
|
static int s_gyrodbg = 0;
|
||||||
if (getenv("BT_GYRO_LOG") && s_gyrodbg++ == 0)
|
if (getenv("BT_GYRO_LOG") && s_gyrodbg++ == 0)
|
||||||
DEBUG_STREAM << "[gyro] dispatch: gyro=" << (void *)gyroSubsystem
|
DEBUG_STREAM << "[gyro] dispatch: gyro=" << (void *)gyroSubsystem
|
||||||
<< " legAnim=" << legAnimationState
|
<< " legAnim=" << legAnimationState
|
||||||
<< " death=" << deathAnimationLatched << "\n" << std::flush;
|
<< " death=" << deathAnimationLatched << "\n" << std::flush;
|
||||||
GyroFrameJointWrite(gyroSubsystem, 0.0f /* mech+0x3F0 model TBD */,
|
GyroFrameJointWrite(gyroSubsystem, unstablePercentage,
|
||||||
legAnimationState, deathAnimationLatched);
|
legAnimationState, deathAnimationLatched);
|
||||||
}
|
}
|
||||||
else if (getenv("BT_GYRO_LOG"))
|
else if (getenv("BT_GYRO_LOG"))
|
||||||
|
|||||||
Reference in New Issue
Block a user