fix(physics): restore binary record scan order
Interleave static ranges, type-three captures, type-four triggers, magnetic records, and dynamic ball records in exact ID order while tracking predicted position separately from mutable motion. Preserve type-three/dynamic broadphase and the raw stack quirk where fixed candidate slot one wins even when a later candidate is nearer; seal that behavior in both C and Rust harnesses. Test Plan: - bash original/tools/test_reconstructed_c.sh - python3 original/tools/audit_reconstruction.py --require-complete - cargo test --all-targets - cargo clippy --all-targets --all-features -- -D warnings - rumdl check original/C_RECONSTRUCTION_FINAL_AUDIT.md original/MECHANICS_PROGRESS.md tdkpin-rs/CHANGELOG.md tdkpin-rs/RECONSTRUCTION.md tdkpin-rs/README.md - git diff --check
This commit is contained in:
@@ -18,6 +18,7 @@ pub struct MilliVec {
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CollisionResponse {
|
||||
#[allow(dead_code)]
|
||||
pub surface_distance: i32,
|
||||
pub velocity: MilliVec,
|
||||
pub spin: Real48,
|
||||
@@ -321,16 +322,34 @@ fn apply_response(
|
||||
}
|
||||
|
||||
/// Calculate the original type-2 response in the registered segment's basis.
|
||||
#[cfg(test)]
|
||||
pub fn line_collision_candidate(
|
||||
old_position: MilliVec,
|
||||
velocity: MilliVec,
|
||||
line_start: Vec2,
|
||||
line_end: Vec2,
|
||||
material: CollisionMaterial,
|
||||
) -> Option<StaticCollisionCandidate> {
|
||||
line_collision_candidate_at(
|
||||
old_position,
|
||||
old_position.add(velocity),
|
||||
velocity,
|
||||
line_start,
|
||||
line_end,
|
||||
material,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn line_collision_candidate_at(
|
||||
old_position: MilliVec,
|
||||
predicted_position: MilliVec,
|
||||
velocity: MilliVec,
|
||||
line_start: Vec2,
|
||||
line_end: Vec2,
|
||||
material: CollisionMaterial,
|
||||
) -> Option<StaticCollisionCandidate> {
|
||||
let start = MilliVec::from_position(line_start);
|
||||
let end = MilliVec::from_position(line_end);
|
||||
let predicted = old_position.add(velocity);
|
||||
let segment = subtract(end, start);
|
||||
let normal_x = Real48::from_i32(segment.x);
|
||||
let normal_y = Real48::from_i32(segment.y);
|
||||
@@ -359,8 +378,8 @@ pub fn line_collision_candidate(
|
||||
if distance > speed
|
||||
|| collision_velocity > 10
|
||||
|| distance.wrapping_sub(10) > collision_velocity.wrapping_abs()
|
||||
|| cross_at_endpoint(start, old_position, predicted) < -10
|
||||
|| cross_at_endpoint(end, old_position, predicted) > 10
|
||||
|| cross_at_endpoint(start, old_position, predicted_position) < -10
|
||||
|| cross_at_endpoint(end, old_position, predicted_position) > 10
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@@ -410,12 +429,31 @@ pub fn collide_with_line(
|
||||
}
|
||||
|
||||
/// Calculate the original type-1 circle response for a path entering it.
|
||||
#[cfg(test)]
|
||||
pub fn circle_collision_candidate(
|
||||
old_position: MilliVec,
|
||||
velocity: MilliVec,
|
||||
center: Vec2,
|
||||
radius: f32,
|
||||
material: CollisionMaterial,
|
||||
) -> Option<StaticCollisionCandidate> {
|
||||
circle_collision_candidate_at(
|
||||
old_position,
|
||||
old_position.add(velocity),
|
||||
velocity,
|
||||
center,
|
||||
radius,
|
||||
material,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn circle_collision_candidate_at(
|
||||
old_position: MilliVec,
|
||||
predicted_position: MilliVec,
|
||||
velocity: MilliVec,
|
||||
center: Vec2,
|
||||
radius: f32,
|
||||
material: CollisionMaterial,
|
||||
) -> Option<StaticCollisionCandidate> {
|
||||
let center = MilliVec::from_position(center);
|
||||
let radius_milli = (radius * 1_000.0).round() as i32;
|
||||
@@ -425,10 +463,9 @@ pub fn circle_collision_candidate(
|
||||
if surface_distance > speed {
|
||||
return None;
|
||||
}
|
||||
let predicted = old_position.add(velocity);
|
||||
let middle = MilliVec {
|
||||
x: old_position.x.wrapping_add(predicted.x) / 2,
|
||||
y: old_position.y.wrapping_add(predicted.y) / 2,
|
||||
x: old_position.x.wrapping_add(predicted_position.x) / 2,
|
||||
y: old_position.y.wrapping_add(predicted_position.y) / 2,
|
||||
};
|
||||
let normal_x = Real48::from_i32(center.y.wrapping_sub(middle.y));
|
||||
let normal_y = Real48::from_i32(middle.x.wrapping_sub(center.x));
|
||||
|
||||
Reference in New Issue
Block a user