diff --git a/common/src/lib.rs b/common/src/lib.rs index f9014bed0b..a774a9efe2 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,3 +1,4 @@ +#![type_length_limit="1615607"] #![feature( euclidean_division, duration_float, diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 7ac4b0c470..6c641217fd 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -159,19 +159,11 @@ impl<'a> System<'a> for Sys { let player_rad = 0.3; // half-width of the player's AABB let player_height = 1.7; - // Iterate through nearby blocks, prioritise closer ones - let near_iter = (0..5) - .map(move |dist| { - (-dist..=dist).map(move |x| { - (-dist..=dist).map(move |y| { - (-dist..=dist) - .map(move |z| Vec3::new(x, y, z)) - .filter(move |p| p.map(|e: i32| e.abs()).reduce_max() == dist) - .map(|p| p.into_tuple()) - }) - }) - }) - .flatten() + let dist = 2; + let near_iter = (-dist..=dist) + .map(move |i| (-dist..=dist) + .map(move |j| (-dist..=dist) + .map(move |k| (i, j, k)))) .flatten() .flatten(); @@ -185,7 +177,7 @@ impl<'a> System<'a> for Sys { .map(|vox| !vox.is_empty()) .unwrap_or(false) { - let this_aabb = Aabb { + let player_aabb = Aabb { min: pos + Vec3::new(-player_rad, -player_rad, 0.0), max: pos + Vec3::new(player_rad, player_rad, player_height), }; @@ -194,7 +186,7 @@ impl<'a> System<'a> for Sys { max: block_pos.map(|e| e as f32) + 1.0, }; - if this_aabb.collides_with_aabb(block_aabb) { + if player_aabb.collides_with_aabb(block_aabb) { return true; } } @@ -205,51 +197,53 @@ impl<'a> System<'a> for Sys { on_grounds.remove(entity); pos.0.z -= 0.0001; // To force collision with the floor - // For every nearby block... let mut on_ground = false; - for (i, j, k) in near_iter.clone() { - let block_pos = pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k); + while collision_with(pos.0, near_iter.clone()) { + let player_aabb = Aabb { + min: pos.0 + Vec3::new(-player_rad, -player_rad, 0.0), + max: pos.0 + Vec3::new(player_rad, player_rad, player_height), + }; - // ...check to see whether it is solid... - if terrain - .get(block_pos) - .map(|vox| !vox.is_empty()) - .unwrap_or(false) + let (block_pos, block_aabb) = near_iter + .clone() + .map(|(i, j, k)| pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k)) + .map(|block_pos| { + let block_aabb = Aabb { + min: block_pos.map(|e| e as f32), + max: block_pos.map(|e| e as f32) + 1.0, + }; + + (block_pos, block_aabb) + }) + .filter(|(_, block_aabb)| block_aabb.collides_with_aabb(player_aabb)) + .filter(|(block_pos, _)| terrain + .get(*block_pos) + .map(|vox| !vox.is_empty()) + .unwrap_or(false)) + .max_by_key(|(_, block_aabb)| ((player_aabb.collision_vector_with_aabb(*block_aabb) * Vec3::new(1.0, 1.0, 10.0)).map(|e| e.abs()).reduce_partial_min() * 200.0) as i32) + .expect("Collision detected, but no colliding blocks found!"); + + let dir = player_aabb.collision_vector_with_aabb(block_aabb); + + let max_axis = dir.map(|e| e.abs()).reduce_partial_min(); + let resolve_dir = -dir.map(|e| if e.abs() == max_axis { e } else { 0.0 }); + + // When the resolution direction is pointing upwards, we must be on the ground + if resolve_dir.z > 0.0 { + on_ground = true; + } + + if resolve_dir.z == 0.0 + && !collision_with(pos.0 + Vec3::unit_z() * 1.1, near_iter.clone()) { - // ...and calculate bounding boxes for both the player's body and the block. - let this_aabb = Aabb { - min: pos.0 + Vec3::new(-player_rad, -player_rad, 0.0), - max: pos.0 + Vec3::new(player_rad, player_rad, player_height), - }; - let block_aabb = Aabb { - min: block_pos.map(|e| e as f32), - max: block_pos.map(|e| e as f32) + 1.0, - }; - - // If the bounding boxes collide, resolve the collision - if this_aabb.collides_with_aabb(block_aabb) { - let dir = this_aabb.collision_vector_with_aabb(block_aabb); - - let max_axis = dir.map(|e| e.abs()).reduce_partial_min(); - let resolve_dir = -dir.map(|e| if e.abs() == max_axis { e } else { 0.0 }); - - // When the resolution direction is pointing upwards, we must be on the ground - if resolve_dir.z > 0.0 { - on_ground = true; - } - - if resolve_dir.z == 0.0 - && !collision_with(pos.0 + Vec3::unit_z() * 1.0, near_iter.clone()) - { - pos.0.z += 1.0; - break; - } else { - pos.0 += resolve_dir; - vel.0 = vel - .0 - .map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 }); - } - } + pos.0.z += 1.0; + on_ground = true; + break; + } else { + pos.0 += resolve_dir; + vel.0 = vel + .0 + .map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 }); } }