From 12ea028a3d5c032a614c75bf98b5eb5b456095ca Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 25 Aug 2020 00:04:04 +0100 Subject: [PATCH] Improved single-tick projectile wall/entity collision bug --- assets/world/style/colors.ron | 2 +- common/src/sys/phys.rs | 4 - common/src/sys/projectile.rs | 165 +++++++++++++++++----------------- 3 files changed, 82 insertions(+), 89 deletions(-) diff --git a/assets/world/style/colors.ron b/assets/world/style/colors.ron index 909387eda2..6f234e82d0 100644 --- a/assets/world/style/colors.ron +++ b/assets/world/style/colors.ron @@ -32,7 +32,7 @@ ), column: ( cold_grass: (0.0, 0.3, 0.1), - warm_grass: (0.3, 0.25, -0.8), + warm_grass: (0.5, 0.55, 0.0), dark_grass: (0.15, 0.4, 0.1), wet_grass: (0.1, 0.8, 0.2), cold_stone: (0.4, 0.67, 0.8), diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index b16bb29991..4be1d1eee0 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -126,10 +126,6 @@ impl<'a> System<'a> for Sys { // already possible with poorly-defined hitboxes anyway so it's not too // much of a concern. // - // Actually, the aforementioned case can't happen, but only because wall - // collision is checked prior to entity collision in the projectile - // code. - // // If this situation becomes a problem, this code should be integrated with the // terrain collision code below, although that's not trivial to do since // it means the step needs to take into account the speeds of both diff --git a/common/src/sys/projectile.rs b/common/src/sys/projectile.rs index 75f769c17a..44dbf39a73 100644 --- a/common/src/sys/projectile.rs +++ b/common/src/sys/projectile.rs @@ -61,6 +61,81 @@ impl<'a> System<'a> for Sys { ) .join() { + // Hit entity + for other in physics.touch_entities.iter().copied() { + if projectile.owner == Some(other) { + continue; + } + + for effect in projectile.hit_entity.iter().cloned() { + match effect { + projectile::Effect::Damage(healthchange) => { + let owner_uid = projectile.owner.unwrap(); + let mut damage = Damage { + healthchange: healthchange as f32, + source: DamageSource::Projectile, + }; + + let other_entity = uid_allocator.retrieve_entity_internal(other.into()); + if let Some(loadout) = other_entity.and_then(|e| loadouts.get(e)) { + damage.modify_damage(false, loadout); + } + + if other != owner_uid { + server_emitter.emit(ServerEvent::Damage { + uid: other, + change: HealthChange { + amount: damage.healthchange as i32, + cause: HealthSource::Attack { by: owner_uid }, + }, + }); + } + }, + projectile::Effect::Knockback(knockback) => { + if let Some(entity) = + uid_allocator.retrieve_entity_internal(other.into()) + { + local_emitter.emit(LocalEvent::ApplyForce { + entity, + force: knockback + * *Dir::slerp(ori.0, Dir::new(Vec3::unit_z()), 0.5), + }); + } + }, + projectile::Effect::RewardEnergy(energy) => { + if let Some(energy_mut) = projectile + .owner + .and_then(|o| uid_allocator.retrieve_entity_internal(o.into())) + .and_then(|o| energies.get_mut(o)) + { + energy_mut.change_by(energy as i32, EnergySource::HitEnemy); + } + }, + projectile::Effect::Explode { power } => { + server_emitter.emit(ServerEvent::Explosion { + pos: pos.0, + power, + owner: projectile.owner, + friendly_damage: false, + reagent: None, + }) + }, + projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy { + entity, + cause: HealthSource::World, + }), + projectile::Effect::Possess => { + if other != projectile.owner.unwrap() { + if let Some(owner) = projectile.owner { + server_emitter.emit(ServerEvent::Possess(owner, other)); + } + } + }, + _ => {}, + } + } + } + // Hit something solid if physics.on_wall.is_some() || physics.on_ground || physics.on_ceiling { for effect in projectile.hit_solid.drain(..) { @@ -81,91 +156,13 @@ impl<'a> System<'a> for Sys { _ => {}, } } - } else { - // Hit entity - for other in physics.touch_entities.iter().copied() { - if projectile.owner == Some(other) { - continue; - } + } - for effect in projectile.hit_entity.iter().cloned() { - match effect { - projectile::Effect::Damage(healthchange) => { - let owner_uid = projectile.owner.unwrap(); - let mut damage = Damage { - healthchange: healthchange as f32, - source: DamageSource::Projectile, - }; - - let other_entity = - uid_allocator.retrieve_entity_internal(other.into()); - if let Some(loadout) = other_entity.and_then(|e| loadouts.get(e)) { - damage.modify_damage(false, loadout); - } - - if other != owner_uid { - server_emitter.emit(ServerEvent::Damage { - uid: other, - change: HealthChange { - amount: damage.healthchange as i32, - cause: HealthSource::Attack { by: owner_uid }, - }, - }); - } - }, - projectile::Effect::Knockback(knockback) => { - if let Some(entity) = - uid_allocator.retrieve_entity_internal(other.into()) - { - local_emitter.emit(LocalEvent::ApplyForce { - entity, - force: knockback - * *Dir::slerp(ori.0, Dir::new(Vec3::unit_z()), 0.5), - }); - } - }, - projectile::Effect::RewardEnergy(energy) => { - if let Some(energy_mut) = projectile - .owner - .and_then(|o| uid_allocator.retrieve_entity_internal(o.into())) - .and_then(|o| energies.get_mut(o)) - { - energy_mut.change_by(energy as i32, EnergySource::HitEnemy); - } - }, - projectile::Effect::Explode { power } => { - server_emitter.emit(ServerEvent::Explosion { - pos: pos.0, - power, - owner: projectile.owner, - friendly_damage: false, - reagent: None, - }) - }, - projectile::Effect::Vanish => { - server_emitter.emit(ServerEvent::Destroy { - entity, - cause: HealthSource::World, - }) - }, - projectile::Effect::Possess => { - if other != projectile.owner.unwrap() { - if let Some(owner) = projectile.owner { - server_emitter.emit(ServerEvent::Possess(owner, other)); - } - } - }, - _ => {}, - } - } - } - - if let Some(dir) = velocities - .get(entity) - .and_then(|vel| vel.0.try_normalized()) - { - ori.0 = dir.into(); - } + if let Some(dir) = velocities + .get(entity) + .and_then(|vel| vel.0.try_normalized()) + { + ori.0 = dir.into(); } if projectile.time_left == Duration::default() {