Account for surface normal when calculating collision damage

This commit is contained in:
Joshua Barretto 2023-05-25 01:21:44 +01:00
parent b086b43a88
commit 9127d6cbf2
4 changed files with 41 additions and 19 deletions

View File

@ -188,6 +188,7 @@ pub enum ServerEvent {
LandOnGround { LandOnGround {
entity: EcsEntity, entity: EcsEntity,
vel: Vec3<f32>, vel: Vec3<f32>,
surface_normal: Vec3<f32>,
}, },
EnableLantern(EcsEntity), EnableLantern(EcsEntity),
DisableLantern(EcsEntity), DisableLantern(EcsEntity),

View File

@ -889,7 +889,9 @@ impl<'a> PhysicsData<'a> {
was_on_ground, was_on_ground,
block_snap, block_snap,
climbing, climbing,
|entity, vel| land_on_ground = Some((entity, vel)), |entity, vel, surface_normal| {
land_on_ground = Some((entity, vel, surface_normal))
},
read, read,
&ori, &ori,
); );
@ -921,7 +923,9 @@ impl<'a> PhysicsData<'a> {
was_on_ground, was_on_ground,
block_snap, block_snap,
climbing, climbing,
|entity, vel| land_on_ground = Some((entity, vel)), |entity, vel, surface_normal| {
land_on_ground = Some((entity, vel, surface_normal))
},
read, read,
&ori, &ori,
); );
@ -1200,10 +1204,12 @@ impl<'a> PhysicsData<'a> {
was_on_ground, was_on_ground,
block_snap, block_snap,
climbing, climbing,
|entity, vel| { |entity, vel, surface_normal| {
land_on_ground = Some(( land_on_ground = Some((
entity, entity,
Vel(ori_other.to_quat() * vel.0), Vel(previous_cache_other.ori * vel.0
+ vel_other),
surface_normal,
)); ));
}, },
read, read,
@ -1337,8 +1343,14 @@ impl<'a> PhysicsData<'a> {
drop(guard); drop(guard);
let mut event_emitter = read.event_bus.emitter(); let mut event_emitter = read.event_bus.emitter();
land_on_grounds.into_iter().for_each(|(entity, vel)| { land_on_grounds
event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 }); .into_iter()
.for_each(|(entity, vel, surface_normal)| {
event_emitter.emit(ServerEvent::LandOnGround {
entity,
vel: vel.0,
surface_normal,
});
}); });
} }
@ -1418,7 +1430,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
was_on_ground: bool, was_on_ground: bool,
block_snap: bool, block_snap: bool,
climbing: bool, climbing: bool,
mut land_on_ground: impl FnMut(Entity, Vel), mut land_on_ground: impl FnMut(Entity, Vel, Vec3<f32>),
read: &PhysicsRead, read: &PhysicsRead,
ori: &Ori, ori: &Ori,
) { ) {
@ -1594,7 +1606,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
} }
if resolve_dir.magnitude_squared() > 0.0 { if resolve_dir.magnitude_squared() > 0.0 {
land_on_ground(entity, *vel); land_on_ground(entity, *vel, resolve_dir.normalized());
} }
// When the resolution direction is non-vertical, we must be colliding // When the resolution direction is non-vertical, we must be colliding

View File

@ -595,14 +595,21 @@ pub fn handle_delete(server: &mut Server, entity: EcsEntity) {
.map_err(|e| error!(?e, ?entity, "Failed to delete destroyed entity")); .map_err(|e| error!(?e, ?entity, "Failed to delete destroyed entity"));
} }
pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>) { pub fn handle_land_on_ground(
server: &Server,
entity: EcsEntity,
vel: Vec3<f32>,
surface_normal: Vec3<f32>,
) {
let ecs = server.state.ecs(); let ecs = server.state.ecs();
let relative_vel = vel.dot(-surface_normal);
// The second part of this if statement disables all fall damage when in the // The second part of this if statement disables all fall damage when in the
// water. This was added as a *temporary* fix a bug that causes you to take // water. This was added as a *temporary* fix a bug that causes you to take
// fall damage while swimming downwards. FIXME: Fix the actual bug and // fall damage while swimming downwards. FIXME: Fix the actual bug and
// remove the following relevant part of the if statement. // remove the following relevant part of the if statement.
if vel.magnitude() >= 30.0 if relative_vel >= 30.0
&& ecs && ecs
.read_storage::<PhysicsState>() .read_storage::<PhysicsState>()
.get(entity) .get(entity)
@ -610,10 +617,10 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
{ {
let char_states = ecs.read_storage::<CharacterState>(); let char_states = ecs.read_storage::<CharacterState>();
let reduced_vel_z = if let Some(CharacterState::DiveMelee(c)) = char_states.get(entity) { let reduced_vel = if let Some(CharacterState::DiveMelee(c)) = char_states.get(entity) {
(vel.magnitude() + c.static_data.vertical_speed).min(0.0) (relative_vel + c.static_data.vertical_speed).min(0.0)
} else { } else {
vel.magnitude() relative_vel
}; };
let mass = ecs let mass = ecs
@ -621,7 +628,7 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
.get(entity) .get(entity)
.copied() .copied()
.unwrap_or_default(); .unwrap_or_default();
let impact_energy = mass.0 * reduced_vel_z.powi(2) / 2.0; let impact_energy = mass.0 * reduced_vel.powi(2) / 2.0;
let falldmg = impact_energy / 1000.0; let falldmg = impact_energy / 1000.0;
let inventories = ecs.read_storage::<Inventory>(); let inventories = ecs.read_storage::<Inventory>();
@ -655,7 +662,7 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
server_eventbus.emit_now(ServerEvent::HealthChange { entity, change }); server_eventbus.emit_now(ServerEvent::HealthChange { entity, change });
// Emit poise change // Emit poise change
let poise_damage = -(mass.0 * reduced_vel_z.powi(2) / 1500.0); let poise_damage = -(mass.0 * reduced_vel.powi(2) / 1500.0);
let poise_change = Poise::apply_poise_reduction( let poise_change = Poise::apply_poise_reduction(
poise_damage, poise_damage,
inventories.get(entity), inventories.get(entity),

View File

@ -120,9 +120,11 @@ impl Server {
ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip), ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip),
ServerEvent::GroupManip(entity, manip) => handle_group(self, entity, manip), ServerEvent::GroupManip(entity, manip) => handle_group(self, entity, manip),
ServerEvent::Respawn(entity) => handle_respawn(self, entity), ServerEvent::Respawn(entity) => handle_respawn(self, entity),
ServerEvent::LandOnGround { entity, vel } => { ServerEvent::LandOnGround {
handle_land_on_ground(self, entity, vel) entity,
}, vel,
surface_normal,
} => handle_land_on_ground(self, entity, vel, surface_normal),
ServerEvent::EnableLantern(entity) => handle_lantern(self, entity, true), ServerEvent::EnableLantern(entity) => handle_lantern(self, entity, true),
ServerEvent::DisableLantern(entity) => handle_lantern(self, entity, false), ServerEvent::DisableLantern(entity) => handle_lantern(self, entity, false),
ServerEvent::NpcInteract(interactor, target, subject) => { ServerEvent::NpcInteract(interactor, target, subject) => {