diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index b2ba589b24..6b63bb8f51 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -33,6 +33,23 @@ impl Body { _ => false, } } + // Note: this might need to be refined to something more complex for realistic + // behavior with less cylindrical bodies (e.g. wolfs) + pub fn radius(&self) -> f32 { + // TODO: Improve these values (some might be reliant on more info in inner type) + match self { + Body::Humanoid(_) => 0.5, + Body::QuadrupedSmall(_) => 0.6, + Body::QuadrupedMedium(_) => 0.9, + Body::BirdMedium(_) => 0.5, + Body::FishMedium(_) => 0.5, + Body::Dragon(_) => 2.5, + Body::BirdSmall(_) => 0.2, + Body::FishSmall(_) => 0.2, + Body::BipedLarge(_) => 1.0, + Body::Object(_) => 0.3, + } + } } impl Component for Body { diff --git a/common/src/sync/packet.rs b/common/src/sync/packet.rs index b3ea29985c..a9d3363eeb 100644 --- a/common/src/sync/packet.rs +++ b/common/src/sync/packet.rs @@ -8,6 +8,9 @@ use std::{ marker::PhantomData, }; +/// Implemented by type that carries component data for insertion and modification +/// The assocatied `Phantom` type only carries information about which component type is of +/// interest and is used to transmit deletion events pub trait CompPacket: Clone + Debug + Send + 'static { type Phantom: Clone + Debug + Serialize + DeserializeOwned; diff --git a/common/src/sync/track.rs b/common/src/sync/track.rs index 8c57360e60..3cccda6794 100644 --- a/common/src/sync/track.rs +++ b/common/src/sync/track.rs @@ -51,10 +51,9 @@ where self.inserted.add(*id); } specs::storage::ComponentEvent::Modified(id) => { - // We don't care about modification if the component was just added or was - // removed - // Could potentially remove since this should theoretically never occur... - if !self.removed.contains(*id) && !self.inserted.contains(*id) { + // We don't care about modification if the component was just added + if !self.inserted.contains(*id) { + debug_assert!(!self.removed.contains(*id)); // Theoretically impossible self.modified.add(*id); } } diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index ef768e2a9d..5ce18dacab 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -147,8 +147,11 @@ impl<'a> System<'a> for Sys { if target_stats.is_dead { choose_new = true; } else if dist < 0.001 { - // TODO: move back? (probably can only happen when entities are at a - // different z-level due to repulsion) + // Probably can only happen when entities are at a different z-level + // since at the same level repulsion would keep them apart. + // Distinct from the first if block since we may want to change the + // behavior for this case. + choose_new = true; } else if dist < MIN_ATTACK_DIST { // Fight (and slowly move closer) inputs.move_dir = diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index 807ca96945..78cba752c0 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -1,7 +1,7 @@ use crate::{ comp::{ - ActionState::*, CharacterState, Controller, HealthChange, HealthSource, Item, ItemKind, - Ori, Pos, Scale, Stats, + ActionState::*, Body, CharacterState, Controller, HealthChange, HealthSource, Item, + ItemKind, Ori, Pos, Scale, Stats, }, event::{EventBus, LocalEvent, ServerEvent}, state::DeltaTime, @@ -30,8 +30,9 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, Ori>, ReadStorage<'a, Scale>, ReadStorage<'a, Controller>, + ReadStorage<'a, Body>, + ReadStorage<'a, Stats>, WriteStorage<'a, CharacterState>, - WriteStorage<'a, Stats>, ); fn run( @@ -46,15 +47,16 @@ impl<'a> System<'a> for Sys { orientations, scales, controllers, - mut character_states, + bodies, stats, + mut character_states, ): Self::SystemData, ) { let mut server_emitter = server_bus.emitter(); let mut _local_emitter = local_bus.emitter(); // Attacks - for (entity, uid, pos, ori, scale_maybe, _, stat) in ( + for (entity, uid, pos, ori, scale_maybe, _, attacker_stats) in ( &entities, &uids, &positions, @@ -68,7 +70,7 @@ impl<'a> System<'a> for Sys { let recover_duration = if let Some(Item { kind: ItemKind::Tool { kind, .. }, .. - }) = stat.equipment.main + }) = attacker_stats.equipment.main { kind.attack_recover_duration() } else { @@ -96,7 +98,7 @@ impl<'a> System<'a> for Sys { if deal_damage { if let Some(Attack { .. }) = &character_states.get(entity).map(|c| c.action) { // Go through all other entities - for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, stat_b) in ( + for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, stats_b, body_b) in ( &entities, &uids, &positions, @@ -104,6 +106,7 @@ impl<'a> System<'a> for Sys { scales.maybe(), &character_states, &stats, + &bodies, ) .join() { @@ -115,19 +118,18 @@ impl<'a> System<'a> for Sys { // Scales let scale = scale_maybe.map_or(1.0, |s| s.0); let scale_b = scale_b_maybe.map_or(1.0, |s| s.0); - // TODO: don't do this here - let rad_b = 0.5 * scale_b; + let rad_b = body_b.radius() * scale_b; // Check if it is a hit if entity != b - && !stat_b.is_dead + && !stats_b.is_dead // Spherical wedge shaped attack field && pos.0.distance_squared(pos_b.0) < (rad_b + scale * ATTACK_RANGE).powi(2) && ori2.angle_between(pos_b2 - pos2) < ATTACK_ANGLE.to_radians() / 2.0 + (rad_b / pos2.distance(pos_b2)).atan() { // Weapon gives base damage let mut dmg = if let Some(ItemKind::Tool { power, .. }) = - stat.equipment.main.as_ref().map(|i| &i.kind) + attacker_stats.equipment.main.as_ref().map(|i| &i.kind) { *power as i32 } else { diff --git a/server/src/lib.rs b/server/src/lib.rs index f8815ad6cf..8804efe33f 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -413,21 +413,25 @@ impl Server { } } - // This sucks - let mut remove = false; + let mut remove = true; if let Some(client) = state.ecs().write_storage::().get_mut(entity) { - let _ = state + remove = false; + state .ecs() .write_storage() - .insert(entity, comp::Vel(Vec3::zero())); - let _ = state + .insert(entity, comp::Vel(Vec3::zero())) + .err() + .map(|err| error!("Failed to set zero vel on dead client: {:?}", err)); + state .ecs() .write_storage() - .insert(entity, comp::ForceUpdate); + .insert(entity, comp::ForceUpdate) + .err() + .map(|err| { + error!("Failed to insert ForceUpdate on dead client: {:?}", err) + }); client.force_state(ClientState::Dead); - } else { - remove = true; } if remove { diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index b9514a903b..6a20dbfbf0 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -756,10 +756,7 @@ impl Ui { } fn default_scissor(renderer: &Renderer) -> Aabr { - let (screen_w, screen_h) = renderer - .get_resolution() - .map(|e| (e as u16).max(1)) - .into_tuple(); + let (screen_w, screen_h) = renderer.get_resolution().into_tuple(); Aabr { min: Vec2 { x: 0, y: 0 }, max: Vec2 {