diff --git a/common/src/comp/phys.rs b/common/src/comp/phys.rs index 94308227c4..d8c688cf1c 100644 --- a/common/src/comp/phys.rs +++ b/common/src/comp/phys.rs @@ -5,7 +5,7 @@ use crate::{ terrain::Block, uid::Uid, }; -use hashbrown::HashSet; +use hashbrown::HashMap; use serde::{Deserialize, Serialize}; use specs::{Component, DerefFlaggedStorage, NullStorage, VecStorage}; use std::sync::Arc; @@ -176,7 +176,7 @@ pub struct PhysicsState { pub on_ground: Option, pub on_ceiling: bool, pub on_wall: Option>, - pub touch_entities: HashSet, + pub touch_entities: HashMap>, pub in_fluid: Option, pub ground_vel: Vec3, pub footwear: Friction, diff --git a/common/systems/src/phys.rs b/common/systems/src/phys.rs index 152628ec8c..a11bbcc053 100644 --- a/common/systems/src/phys.rs +++ b/common/systems/src/phys.rs @@ -1917,7 +1917,7 @@ fn resolve_e2e_collision( // is either in mid air or is not sticky, then mark them as colliding with // the other entity. if !*collision_registered && (is_mid_air || !is_sticky) { - physics.touch_entities.insert(other); + physics.touch_entities.insert(other, pos); *entity_entity_collisions += 1; } diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index 1ad2429316..2870625e6c 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -12,15 +12,19 @@ use common::{ util::Dir, GroupTarget, }; + +use common::vol::ReadVol; use common_ecs::{Job, Origin, Phase, System}; use rand::{thread_rng, Rng}; use specs::{ saveload::MarkerAllocator, shred::ResourceId, Entities, Entity as EcsEntity, Join, Read, - ReadStorage, SystemData, World, WriteStorage, + ReadExpect, ReadStorage, SystemData, World, WriteStorage, }; use std::time::Duration; use vek::*; +use common::terrain::TerrainGrid; + #[derive(SystemData)] pub struct ReadData<'a> { time: Read<'a, Time>, @@ -42,6 +46,7 @@ pub struct ReadData<'a> { healths: ReadStorage<'a, Health>, bodies: ReadStorage<'a, Body>, character_states: ReadStorage<'a, CharacterState>, + terrain: ReadExpect<'a, TerrainGrid>, } /// This system is responsible for handling projectile effect triggers @@ -90,7 +95,7 @@ impl<'a> System<'a> for Sys { let mut projectile_vanished: bool = false; // Hit entity - for other in physics.touch_entities.iter().copied() { + for (&other, &pos_other) in physics.touch_entities.iter() { let same_group = projectile_owner // Note: somewhat inefficient since we do the lookup for every touching // entity, but if we pull this out of the loop we would want to do it only @@ -121,6 +126,28 @@ impl<'a> System<'a> for Sys { let entity_of = |uid: Uid| read_data.uid_allocator.retrieve_entity_internal(uid.into()); + + // Don't hit if there is a surface in the entity's way in the direction the + // projectile is going + + if physics.on_surface().is_some() { + let projectile_direction = orientations + .get(entity) + .map_or_else(Vec3::zero, |ori| ori.look_vec()); + let pos_wall = pos.0 - 0.2 * projectile_direction; + if !matches!( + read_data + .terrain + .ray(pos_wall, pos_other) + .until(|b| b.is_filled()) + .cast() + .1, + Ok(None) + ) { + continue; + } + } + for effect in projectile.hit_entity.drain(..) { let owner = projectile.owner.and_then(entity_of); let projectile_info = ProjectileInfo {