diff --git a/common/sys/src/phys.rs b/common/sys/src/phys.rs index e36d545e4f..1a500d293e 100644 --- a/common/sys/src/phys.rs +++ b/common/sys/src/phys.rs @@ -622,6 +622,7 @@ impl<'a> PhysicsData<'a> { _previous_cache, _, )| { + prof_span!(_guard, "entity"); let mut land_on_ground = None; // Defer the writes of positions and velocities to allow an inner loop over // terrain-like entities @@ -803,6 +804,7 @@ impl<'a> PhysicsData<'a> { } }; // Collide with terrain-like entities + //prof_span!(guard, "terrain entity join"); let aabr = { let center = path_sphere.center.xy().map(|e| e as i32); let radius = path_sphere.radius.ceil() as i32; @@ -960,6 +962,7 @@ impl<'a> PhysicsData<'a> { } }, ); + //drop(guard); if tgt_pos != pos.0 { pos_vel_defer.pos = Some(Pos(tgt_pos)); @@ -1069,6 +1072,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( climbing: bool, mut land_on_ground: impl FnMut(Entity, Vel), ) { + //prof_span!(_guard, "box_voxel_collision"); let (radius, z_min, z_max) = cylinder; // Probe distances @@ -1129,6 +1133,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( radius: f32, z_range: Range, ) -> bool { + //prof_span!(_guard, "collision_with"); collision_iter( pos, terrain, @@ -1138,8 +1143,8 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( radius, z_range, ) - .count() - > 0 + .next() + .is_some() } physics_state.on_ground = false; @@ -1179,6 +1184,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( // Determine the block that we are colliding with most (based on minimum // collision axis) + //prof_span!(guard, "find colliding block"); let (_block_pos, block_aabb, block_height) = near_iter .clone() // Calculate the block's position in world space @@ -1213,6 +1219,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( * 1_000_000.0) as i32 }) .expect("Collision detected, but no colliding blocks found!"); + //drop(guard); // Find the intrusion vector of the collision let dir = player_aabb.collision_vector_with_aabb(block_aabb); @@ -1330,7 +1337,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( -Vec3::unit_y(), ]; - if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| { + /*if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| { if collision_with( pos.0 + *dir * 0.01, &terrain, @@ -1355,6 +1362,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( } // Figure out if we're in water + //prof_span!(guard, "water"); physics_state.in_liquid = collision_iter( pos.0, &*terrain, @@ -1363,10 +1371,95 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( &|_block| 1.0, near_iter, radius, - z_min..z_max, + z_range, ) .max_by_key(|block_aabb| (block_aabb.max.z * 100.0) as i32) .map(|block_aabb| block_aabb.max.z - pos.0.z); + //drop(guard); + */ + prof_span!(guard, "compound check"); + let player_aabb = Aabb { + min: pos.0 + Vec3::new(-radius, -radius, z_range.start), + max: pos.0 + Vec3::new(radius, radius, z_range.end), + }; + let player_voxel_pos = pos.0.map(|e| e.floor() as i32); + // TODO: use array nightly features + let wall_check_positions = [ + (pos.0 + dirs[0] * 0.01), + (pos.0 + dirs[1] * 0.01), + (pos.0 + dirs[2] * 0.01), + (pos.0 + dirs[3] * 0.01), + ]; + let p_aabb = |pos| { + let player_aabb = Aabb { + min: pos + Vec3::new(-radius, -radius, z_range.start), + max: pos + Vec3::new(radius, radius, z_range.end), + }; + player_aabb + }; + let player_wall_aabbs = [ + p_aabb(wall_check_positions[0]), + p_aabb(wall_check_positions[1]), + p_aabb(wall_check_positions[2]), + p_aabb(wall_check_positions[3]), + ]; + + // Find liquid immersion and wall collision all in one round of iteration + let mut max_liquid_z = None::; + let mut wall_dir_collisions = [false; 4]; + near_iter.for_each(|(i, j, k)| { + let block_pos = player_voxel_pos + Vec3::new(i, j, k); + + if let Some(block) = terrain.get(block_pos).ok().copied() { + // Check for liquid blocks + if block.is_liquid() { + let liquid_aabb = Aabb { + min: block_pos.map(|e| e as f32), + // The liquid part of a liquid block always extends 1 block high. + max: block_pos.map(|e| e as f32) + Vec3::one(), + }; + if player_aabb.collides_with_aabb(liquid_aabb) { + max_liquid_z = Some(match max_liquid_z { + Some(z) => z.max(liquid_aabb.max.z), + None => liquid_aabb.max.z, + }); + } + } + // Check for walls + if block.is_solid() { + let block_aabb = Aabb { + min: block_pos.map(|e| e as f32), + max: block_pos.map(|e| e as f32) + Vec3::new(1.0, 1.0, block.solid_height()), + }; + + for dir in 0..4 { + if player_wall_aabbs[dir].collides_with_aabb(block_aabb) { + wall_dir_collisions[dir] = true; + } + } + } + } + }); + + // Use wall collision results to determine if we are against a wall + let mut on_wall = None; + for dir in 0..4 { + if wall_dir_collisions[dir] { + on_wall = Some(match on_wall { + Some(acc) => acc + dirs[dir], + None => dirs[dir], + }); + } + } + physics_state.on_wall = on_wall; + if physics_state.on_ground || (physics_state.on_wall.is_some() && climbing) { + vel.0 *= (1.0 - FRIC_GROUND.min(1.0)).powf(dt.0 * 60.0); + physics_state.ground_vel = ground_vel; + } + + // Set in_liquid state + physics_state.in_liquid = max_liquid_z.map(|max_z| max_z - pos.0.z); + //drop(guard); } fn voxel_collider_bounding_sphere(