feat(#182): PhysicsBody fsf state + CachedVelocity; ungate small-velocity-zero (Slice 1a)
Verbatim UpdatePhysicsInternal (0x00510700): the small-velocity-zero
(<0.25 m/s) fires unconditionally, not gated on OnWalkable (the old acdream
divergence) — gravity re-accelerates the same frame via the unconditional
v += a*dt. Adds TransientStateFlags.Stationary{Fall,Stop,Stuck} (0x10/0x20/0x40)
for the fsf round-trip, plus PhysicsBody.FramesStationaryFall and the separate
CachedVelocity field (retail's two-velocity model — reporting/DR only, never fed
to the integrator). All 1536 physics tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8bb8b20411
commit
6e8117741b
2 changed files with 72 additions and 6 deletions
|
|
@ -162,6 +162,46 @@ public sealed class PhysicsBodyTests
|
|||
Assert.False(body.IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdatePhysicsInternal_zeroes_small_velocity_even_when_airborne()
|
||||
{
|
||||
// Retail UpdatePhysicsInternal (0x005107be) zeroes velocity below 0.25 m/s
|
||||
// UNCONDITIONALLY — NOT gated on OnWalkable. acdream previously gated it on
|
||||
// OnWalkable; the verbatim rebuild removes the gate. Gravity re-accelerates the
|
||||
// same frame via the unconditional `Velocity += Acceleration * dt`, so the fall
|
||||
// still accumulates on Z.
|
||||
var body = MakeAirborne(); // not Contact, not OnWalkable
|
||||
body.set_velocity(new Vector3(0.1f, 0f, 0f)); // < 0.25 m/s
|
||||
body.Acceleration = new Vector3(0f, 0f, PhysicsBody.Gravity);
|
||||
|
||||
body.UpdatePhysicsInternal(1f / 30f);
|
||||
|
||||
Assert.True(MathF.Abs(body.Velocity.X) < 1e-4f, $"X not zeroed: {body.Velocity.X}");
|
||||
Assert.True(body.Velocity.Z < 0f, $"gravity did not accumulate: {body.Velocity.Z}");
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════
|
||||
// frames_stationary_fall carry state (retail transient_state bits)
|
||||
// ════════════════════════════════════════════════════════════════════
|
||||
|
||||
[Fact]
|
||||
public void TransientStateFlags_has_stationary_bits()
|
||||
{
|
||||
// retail transient_state StationaryFall/Stop/Stuck (handle_all_collisions
|
||||
// pc:282743/282749/282753; seeded back into transition pc:280940-947).
|
||||
Assert.Equal(0x10u, (uint)TransientStateFlags.StationaryFall);
|
||||
Assert.Equal(0x20u, (uint)TransientStateFlags.StationaryStop);
|
||||
Assert.Equal(0x40u, (uint)TransientStateFlags.StationaryStuck);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PhysicsBody_has_fsf_and_cached_velocity_defaults()
|
||||
{
|
||||
var body = new PhysicsBody();
|
||||
Assert.Equal(0, body.FramesStationaryFall);
|
||||
Assert.Equal(Vector3.Zero, body.CachedVelocity);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════
|
||||
// set_velocity — velocity clamping
|
||||
// ════════════════════════════════════════════════════════════════════
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue