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 {
entity: EcsEntity,
vel: Vec3<f32>,
surface_normal: Vec3<f32>,
},
EnableLantern(EcsEntity),
DisableLantern(EcsEntity),

View File

@ -889,7 +889,9 @@ impl<'a> PhysicsData<'a> {
was_on_ground,
block_snap,
climbing,
|entity, vel| land_on_ground = Some((entity, vel)),
|entity, vel, surface_normal| {
land_on_ground = Some((entity, vel, surface_normal))
},
read,
&ori,
);
@ -921,7 +923,9 @@ impl<'a> PhysicsData<'a> {
was_on_ground,
block_snap,
climbing,
|entity, vel| land_on_ground = Some((entity, vel)),
|entity, vel, surface_normal| {
land_on_ground = Some((entity, vel, surface_normal))
},
read,
&ori,
);
@ -1200,10 +1204,12 @@ impl<'a> PhysicsData<'a> {
was_on_ground,
block_snap,
climbing,
|entity, vel| {
|entity, vel, surface_normal| {
land_on_ground = Some((
entity,
Vel(ori_other.to_quat() * vel.0),
Vel(previous_cache_other.ori * vel.0
+ vel_other),
surface_normal,
));
},
read,
@ -1337,9 +1343,15 @@ impl<'a> PhysicsData<'a> {
drop(guard);
let mut event_emitter = read.event_bus.emitter();
land_on_grounds.into_iter().for_each(|(entity, vel)| {
event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 });
});
land_on_grounds
.into_iter()
.for_each(|(entity, vel, surface_normal)| {
event_emitter.emit(ServerEvent::LandOnGround {
entity,
vel: vel.0,
surface_normal,
});
});
}
fn update_cached_spatial_grid(&mut self) {
@ -1418,7 +1430,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
was_on_ground: bool,
block_snap: bool,
climbing: bool,
mut land_on_ground: impl FnMut(Entity, Vel),
mut land_on_ground: impl FnMut(Entity, Vel, Vec3<f32>),
read: &PhysicsRead,
ori: &Ori,
) {
@ -1594,7 +1606,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
}
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

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"));
}
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 relative_vel = vel.dot(-surface_normal);
// 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
// fall damage while swimming downwards. FIXME: Fix the actual bug and
// remove the following relevant part of the if statement.
if vel.magnitude() >= 30.0
if relative_vel >= 30.0
&& ecs
.read_storage::<PhysicsState>()
.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 reduced_vel_z = if let Some(CharacterState::DiveMelee(c)) = char_states.get(entity) {
(vel.magnitude() + c.static_data.vertical_speed).min(0.0)
let reduced_vel = if let Some(CharacterState::DiveMelee(c)) = char_states.get(entity) {
(relative_vel + c.static_data.vertical_speed).min(0.0)
} else {
vel.magnitude()
relative_vel
};
let mass = ecs
@ -621,7 +628,7 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
.get(entity)
.copied()
.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 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 });
// 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(
poise_damage,
inventories.get(entity),

View File

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