From d38f1d319c871f541d35bb934bdb1291c975de9e Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 1 Nov 2020 18:26:01 -0600 Subject: [PATCH] Energy and health change server events now reference EcsEntity instead of Uid. Added TargetGroup to use to determine targets of effects/damage. Added Entity(TargetGroup, Effect) to RadiusEffect enum. --- common/src/combat.rs | 13 ++++- common/src/event.rs | 4 +- common/src/explosion.rs | 7 ++- common/src/lib.rs | 2 +- common/src/sys/beam.rs | 66 ++++++++++++------------ common/src/sys/buff.rs | 9 ++-- common/src/sys/melee.rs | 17 +++--- common/src/sys/projectile.rs | 47 ++++++++++++----- common/src/sys/shockwave.rs | 14 +++-- server/src/cmd.rs | 11 ++-- server/src/events/entity_manipulation.rs | 54 ++++++++++++------- server/src/events/mod.rs | 6 +-- server/src/state_ext.rs | 4 ++ server/src/sys/object.rs | 22 +++++--- 14 files changed, 172 insertions(+), 104 deletions(-) diff --git a/common/src/combat.rs b/common/src/combat.rs index ed11e2fb5e..c89419fcd5 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -21,8 +21,11 @@ pub struct Damages { impl Damages { pub fn new(enemy: Option, group: Option) -> Self { Damages { enemy, group } } - pub fn get_damage(self, same_group: bool) -> Option { - if same_group { self.group } else { self.enemy } + pub fn get_damage(self, group_target: GroupTarget) -> Option { + match group_target { + GroupTarget::InGroup => self.group, + GroupTarget::OutOfGroup => self.enemy, + } } pub fn contains_damage(self, source: DamageSource) -> bool { @@ -31,6 +34,12 @@ impl Damages { } } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum GroupTarget { + InGroup, + OutOfGroup, +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum DamageSource { Melee, diff --git a/common/src/event.rs b/common/src/event.rs index 41965191da..4275aeb519 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -34,7 +34,7 @@ pub enum ServerEvent { reagent: Option, }, Damage { - uid: Uid, + entity: EcsEntity, change: comp::HealthChange, }, Destroy { @@ -111,7 +111,7 @@ pub enum ServerEvent { buff_change: comp::BuffChange, }, EnergyChange { - uid: Uid, + entity: EcsEntity, change: comp::EnergyChange, }, } diff --git a/common/src/explosion.rs b/common/src/explosion.rs index c0a96caab1..8de12f367c 100644 --- a/common/src/explosion.rs +++ b/common/src/explosion.rs @@ -1,4 +1,7 @@ -use crate::{combat::Damages, effect::Effect}; +use crate::{ + combat::{Damages, GroupTarget}, + effect::Effect, +}; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -12,5 +15,5 @@ pub struct Explosion { pub enum RadiusEffect { Damages(Damages), TerrainDestruction(f32), - EntityEffect(Effect), + Entity(Option, Effect), } diff --git a/common/src/lib.rs b/common/src/lib.rs index 1959d85135..f7e166c7fa 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -53,6 +53,6 @@ pub mod util; pub mod vol; pub mod volumes; -pub use combat::{Damage, DamageSource, Damages, Knockback}; +pub use combat::{Damage, DamageSource, Damages, GroupTarget, Knockback}; pub use explosion::{Explosion, RadiusEffect}; pub use loadout_builder::LoadoutBuilder; diff --git a/common/src/sys/beam.rs b/common/src/sys/beam.rs index 2f81ce7bc3..d6cb680d90 100644 --- a/common/src/sys/beam.rs +++ b/common/src/sys/beam.rs @@ -6,7 +6,7 @@ use crate::{ event::{EventBus, ServerEvent}, state::{DeltaTime, Time}, sync::{Uid, UidAllocator}, - DamageSource, + DamageSource, GroupTarget, }; use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage}; use std::time::Duration; @@ -68,8 +68,8 @@ impl<'a> System<'a> for Sys { let dt = dt.0; // Beams - for (entity, uid, pos, ori, beam_segment) in - (&entities, &uids, &positions, &orientations, &beam_segments).join() + for (entity, pos, ori, beam_segment) in + (&entities, &positions, &orientations, &beam_segments).join() { let creation_time = match beam_segment.creation { Some(time) => time, @@ -163,12 +163,19 @@ impl<'a> System<'a> for Sys { .map(|group_a| Some(group_a) == groups.get(b)) .unwrap_or(Some(*uid_b) == beam_segment.owner); + let target_group = if same_group { + GroupTarget::InGroup + } else { + GroupTarget::OutOfGroup + }; + // If owner, shouldn't heal or damage if Some(*uid_b) == beam_segment.owner { continue; } - let damage = if let Some(damage) = beam_segment.damages.get_damage(same_group) { + let damage = if let Some(damage) = beam_segment.damages.get_damage(target_group) + { damage } else { continue; @@ -181,25 +188,22 @@ impl<'a> System<'a> for Sys { let change = damage.modify_damage(block, loadouts.get(b), beam_segment.owner); if !matches!(damage.source, DamageSource::Healing) { - server_emitter.emit(ServerEvent::Damage { - uid: *uid_b, - change, - }); - if beam_segment.lifesteal_eff > 0.0 { - server_emitter.emit(ServerEvent::Damage { - uid: beam_segment.owner.unwrap_or(*uid), - change: HealthChange { - amount: (-change.amount as f32 * beam_segment.lifesteal_eff) - as i32, - cause: HealthSource::Healing { - by: beam_segment.owner, + server_emitter.emit(ServerEvent::Damage { entity: b, change }); + if let Some(entity) = beam_owner { + if beam_segment.lifesteal_eff > 0.0 { + server_emitter.emit(ServerEvent::Damage { + entity, + change: HealthChange { + amount: (-change.amount as f32 * beam_segment.lifesteal_eff) + as i32, + cause: HealthSource::Healing { + by: beam_segment.owner, + }, }, - }, - }); - } - if let Some(uid) = beam_segment.owner { + }); + } server_emitter.emit(ServerEvent::EnergyChange { - uid, + entity, change: EnergyChange { amount: beam_segment.energy_regen as i32, source: EnergySource::HitEnemy, @@ -208,19 +212,15 @@ impl<'a> System<'a> for Sys { } } else if let Some(energy) = beam_owner.and_then(|o| energies.get(o)) { if energy.current() > beam_segment.energy_cost { - if let Some(uid) = beam_segment.owner { - server_emitter.emit(ServerEvent::EnergyChange { - uid, - change: EnergyChange { - amount: -(beam_segment.energy_cost as i32), // Stamina use - source: EnergySource::Ability, - }, - }) - } - server_emitter.emit(ServerEvent::Damage { - uid: *uid_b, - change, + server_emitter.emit(ServerEvent::EnergyChange { + entity: beam_owner.unwrap(), /* If it's able to get an energy + * component, the entity exists */ + change: EnergyChange { + amount: -(beam_segment.energy_cost as i32), // Stamina use + source: EnergySource::Ability, + }, }); + server_emitter.emit(ServerEvent::Damage { entity: b, change }); } } // Adds entities that were hit to the hit_entities list on the beam, sees if it diff --git a/common/src/sys/buff.rs b/common/src/sys/buff.rs index 271f19d49a..9cb76930b3 100644 --- a/common/src/sys/buff.rs +++ b/common/src/sys/buff.rs @@ -5,7 +5,6 @@ use crate::{ }, event::{EventBus, ServerEvent}, state::DeltaTime, - sync::Uid, }; use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; use std::time::Duration; @@ -17,7 +16,6 @@ impl<'a> System<'a> for Sys { Entities<'a>, Read<'a, DeltaTime>, Read<'a, EventBus>, - ReadStorage<'a, Uid>, ReadStorage<'a, Loadout>, WriteStorage<'a, Health>, WriteStorage<'a, Buffs>, @@ -25,14 +23,13 @@ impl<'a> System<'a> for Sys { fn run( &mut self, - (entities, dt, server_bus, uids, loadouts, mut healths, mut buffs): Self::SystemData, + (entities, dt, server_bus, loadouts, mut healths, mut buffs): Self::SystemData, ) { let mut server_emitter = server_bus.emitter(); // Set to false to avoid spamming server buffs.set_event_emission(false); healths.set_event_emission(false); - for (entity, buff_comp, uid, health) in (&entities, &mut buffs, &uids, &mut healths).join() - { + for (entity, buff_comp, health) in (&entities, &mut buffs, &mut healths).join() { let mut expired_buffs = Vec::::new(); for (id, buff) in buff_comp.buffs.iter_mut() { // Tick the buff and subtract delta from it @@ -94,7 +91,7 @@ impl<'a> System<'a> for Sys { HealthSource::Buff { owner: buff_owner } }; server_emitter.emit(ServerEvent::Damage { - uid: *uid, + entity, change: HealthChange { amount: *accumulated as i32, cause, diff --git a/common/src/sys/melee.rs b/common/src/sys/melee.rs index 93be75b795..ca77866ba2 100644 --- a/common/src/sys/melee.rs +++ b/common/src/sys/melee.rs @@ -5,6 +5,7 @@ use crate::{ span, sync::Uid, util::Dir, + GroupTarget, }; use rand::{thread_rng, Rng}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; @@ -75,9 +76,8 @@ impl<'a> System<'a> for Sys { attack.applied = true; // Go through all other entities - for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, health_b, body_b) in ( + for (b, pos_b, ori_b, scale_b_maybe, character_b, health_b, body_b) in ( &entities, - &uids, &positions, &orientations, scales.maybe(), @@ -110,7 +110,13 @@ impl<'a> System<'a> for Sys { .map(|group_a| Some(group_a) == groups.get(b)) .unwrap_or(false); - let damage = if let Some(damage) = attack.damages.get_damage(same_group) { + let target_group = if same_group { + GroupTarget::InGroup + } else { + GroupTarget::OutOfGroup + }; + + let damage = if let Some(damage) = attack.damages.get_damage(target_group) { damage } else { continue; @@ -122,10 +128,7 @@ impl<'a> System<'a> for Sys { let change = damage.modify_damage(block, loadouts.get(b), Some(*uid)); if change.amount != 0 { - server_emitter.emit(ServerEvent::Damage { - uid: *uid_b, - change, - }); + server_emitter.emit(ServerEvent::Damage { entity: b, change }); // Apply bleeding buff on melee hits with 10% chance // TODO: Don't have buff uniformly applied on all melee attacks diff --git a/common/src/sys/projectile.rs b/common/src/sys/projectile.rs index 5959a6ce2f..2650b443b8 100644 --- a/common/src/sys/projectile.rs +++ b/common/src/sys/projectile.rs @@ -9,6 +9,7 @@ use crate::{ span, state::DeltaTime, sync::UidAllocator, + GroupTarget, }; use rand::{thread_rng, Rng}; use specs::{ @@ -83,6 +84,13 @@ impl<'a> System<'a> for Sys { .retrieve_entity_internal(other.into()) .and_then(|e| groups.get(e)) ); + + let target_group = if same_group { + GroupTarget::InGroup + } else { + GroupTarget::OutOfGroup + }; + if projectile.ignore_group // Skip if in the same group && same_group @@ -100,36 +108,49 @@ impl<'a> System<'a> for Sys { if Some(other) == projectile.owner { continue; } - let damage = if let Some(damage) = damages.get_damage(same_group) { + let damage = if let Some(damage) = damages.get_damage(target_group) { damage } else { continue; }; - let other_entity_loadout = uid_allocator - .retrieve_entity_internal(other.into()) - .and_then(|e| loadouts.get(e)); - let change = - damage.modify_damage(false, other_entity_loadout, projectile.owner); + if let Some(other_entity) = + uid_allocator.retrieve_entity_internal(other.into()) + { + let other_entity_loadout = loadouts.get(other_entity); + let change = damage.modify_damage( + false, + other_entity_loadout, + projectile.owner, + ); - if change.amount != 0 { - server_emitter.emit(ServerEvent::Damage { uid: other, change }); + if change.amount != 0 { + server_emitter.emit(ServerEvent::Damage { + entity: other_entity, + change, + }); + } } }, projectile::Effect::Knockback(knockback) => { - if let Some(entity) = + if let Some(other_entity) = uid_allocator.retrieve_entity_internal(other.into()) { let impulse = knockback.calculate_impulse(ori.0); if !impulse.is_approx_zero() { - local_emitter - .emit(LocalEvent::ApplyImpulse { entity, impulse }); + local_emitter.emit(LocalEvent::ApplyImpulse { + entity: other_entity, + impulse, + }); } } }, projectile::Effect::RewardEnergy(energy) => { - if let Some(uid) = projectile.owner { + if let Some(entity_owner) = projectile + .owner + .and_then(|u| uid_allocator.retrieve_entity_internal(u.into())) + { server_emitter.emit(ServerEvent::EnergyChange { - uid, + entity: entity_owner, change: EnergyChange { amount: energy as i32, source: EnergySource::HitEnemy, diff --git a/common/src/sys/shockwave.rs b/common/src/sys/shockwave.rs index f85fe7cce6..b71f900fda 100644 --- a/common/src/sys/shockwave.rs +++ b/common/src/sys/shockwave.rs @@ -7,6 +7,7 @@ use crate::{ state::{DeltaTime, Time}, sync::{Uid, UidAllocator}, util::Dir, + GroupTarget, }; use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage}; use vek::*; @@ -177,6 +178,12 @@ impl<'a> System<'a> for Sys { .map(|group_a| Some(group_a) == groups.get(b)) .unwrap_or(Some(*uid_b) == shockwave.owner); + let target_group = if same_group { + GroupTarget::InGroup + } else { + GroupTarget::OutOfGroup + }; + // Check if it is a hit let hit = entity != b && !health_b.is_dead @@ -192,7 +199,7 @@ impl<'a> System<'a> for Sys { && (!shockwave.requires_ground || physics_state_b.on_ground); if hit { - let damage = if let Some(damage) = shockwave.damages.get_damage(same_group) { + let damage = if let Some(damage) = shockwave.damages.get_damage(target_group) { damage } else { continue; @@ -205,10 +212,7 @@ impl<'a> System<'a> for Sys { let change = damage.modify_damage(block, loadouts.get(b), Some(owner_uid)); if change.amount != 0 { - server_emitter.emit(ServerEvent::Damage { - uid: *uid_b, - change, - }); + server_emitter.emit(ServerEvent::Damage { entity: b, change }); shockwave_hit_list.hit_entities.push(*uid_b); let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0)); let impulse = shockwave.knockback.calculate_impulse(kb_dir); diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 0c3c317fee..daffafd1df 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -1158,10 +1158,13 @@ fn handle_explosion( pos: pos.0, explosion: Explosion { effects: vec![ - RadiusEffect::EntityEffect(Effect::Health(comp::HealthChange { - amount: (-100.0 * power) as i32, - cause: comp::HealthSource::Explosion { owner: None }, - })), + RadiusEffect::Entity( + None, + Effect::Health(comp::HealthChange { + amount: (-100.0 * power) as i32, + cause: comp::HealthSource::Explosion { owner: None }, + }), + ), RadiusEffect::TerrainDestruction(power), ], radius: 3.0 * power, diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 348d6d7a9c..5d613001ab 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -19,7 +19,7 @@ use common::{ sys::melee::BLOCK_ANGLE, terrain::{Block, TerrainGrid}, vol::ReadVol, - Damage, DamageSource, Explosion, RadiusEffect, + Damage, DamageSource, Explosion, GroupTarget, RadiusEffect, }; use comp::item::Reagent; use rand::prelude::*; @@ -27,12 +27,10 @@ use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt use tracing::error; use vek::Vec3; -pub fn handle_damage(server: &Server, uid: Uid, change: HealthChange) { +pub fn handle_damage(server: &Server, entity: EcsEntity, change: HealthChange) { let ecs = &server.state.ecs(); - if let Some(entity) = ecs.entity_from_uid(uid.into()) { - if let Some(health) = ecs.write_storage::().get_mut(entity) { - health.change_by(change); - } + if let Some(health) = ecs.write_storage::().get_mut(entity) { + health.change_by(change); } } @@ -570,7 +568,13 @@ pub fn handle_explosion( } } - let mut damage = if let Some(damage) = damages.get_damage(same_group) { + let target_group = if same_group { + GroupTarget::InGroup + } else { + GroupTarget::OutOfGroup + }; + + let mut damage = if let Some(damage) = damages.get_damage(target_group) { damage } else { continue; @@ -667,13 +671,29 @@ pub fn handle_explosion( .cast(); } }, - RadiusEffect::EntityEffect(effect) => { - for (entity, pos_entity) in - (&ecs.entities(), &ecs.read_storage::()).join() + RadiusEffect::Entity(target_group, effect) => { + for (entity_b, pos_b) in (&ecs.entities(), &ecs.read_storage::()).join() { - let distance_squared = pos.distance_squared(pos_entity.0); - if distance_squared < explosion.radius.powi(2) { - server.state().apply_effect(entity, effect); + let distance_squared = pos.distance_squared(pos_b.0); + // See if entities are in the same group + let mut same_group = owner_entity + .and_then(|e| groups.get(e)) + .map_or(false, |group_a| Some(group_a) == groups.get(entity_b)); + if let Some(entity) = owner_entity { + if entity == entity_b { + same_group = true; + } + } + let hit_group = if same_group { + GroupTarget::InGroup + } else { + GroupTarget::OutOfGroup + }; + + if distance_squared < explosion.radius.powi(2) + && target_group.map_or(true, |g| g == hit_group) + { + server.state().apply_effect(entity_b, effect); } } }, @@ -754,11 +774,9 @@ pub fn handle_buff(server: &mut Server, entity: EcsEntity, buff_change: buff::Bu } } -pub fn handle_energy_change(server: &Server, uid: Uid, change: EnergyChange) { +pub fn handle_energy_change(server: &Server, entity: EcsEntity, change: EnergyChange) { let ecs = &server.state.ecs(); - if let Some(entity) = ecs.entity_from_uid(uid.into()) { - if let Some(energy) = ecs.write_storage::().get_mut(entity) { - energy.change_by(change); - } + if let Some(energy) = ecs.write_storage::().get_mut(entity) { + energy.change_by(change); } } diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index 7c083d8be0..edcc319842 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -82,7 +82,7 @@ impl Server { ServerEvent::Knockback { entity, impulse } => { handle_knockback(&self, entity, impulse) }, - ServerEvent::Damage { uid, change } => handle_damage(&self, uid, change), + ServerEvent::Damage { entity, change } => handle_damage(&self, entity, change), ServerEvent::Destroy { entity, cause } => handle_destroy(self, entity, cause), ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip), ServerEvent::GroupManip(entity, manip) => handle_group(self, entity, manip), @@ -137,8 +137,8 @@ impl Server { entity, buff_change, } => handle_buff(self, entity, buff_change), - ServerEvent::EnergyChange { uid, change } => { - handle_energy_change(&self, uid, change) + ServerEvent::EnergyChange { entity, change } => { + handle_energy_change(&self, entity, change) }, } } diff --git a/server/src/state_ext.rs b/server/src/state_ext.rs index 3ffa32252d..253a417542 100644 --- a/server/src/state_ext.rs +++ b/server/src/state_ext.rs @@ -242,6 +242,10 @@ impl StateExt for State { z_max: body.height(), }); self.write_component(entity, body); + self.write_component( + entity, + comp::Health::new(stats.body_type, stats.level.level()), + ); self.write_component(entity, stats); self.write_component(entity, inventory); self.write_component(entity, loadout); diff --git a/server/src/sys/object.rs b/server/src/sys/object.rs index 7b86eb73b5..519e7d5cad 100644 --- a/server/src/sys/object.rs +++ b/server/src/sys/object.rs @@ -50,10 +50,13 @@ impl<'a> System<'a> for Sys { pos: pos.0, explosion: Explosion { effects: vec![ - RadiusEffect::EntityEffect(Effect::Health(HealthChange { - amount: -500, - cause: HealthSource::Explosion { owner: *owner }, - })), + RadiusEffect::Entity( + None, + Effect::Health(HealthChange { + amount: -500, + cause: HealthSource::Explosion { owner: *owner }, + }), + ), RadiusEffect::TerrainDestruction(4.0), ], radius: 12.0, @@ -74,10 +77,13 @@ impl<'a> System<'a> for Sys { pos: pos.0, explosion: Explosion { effects: vec![ - RadiusEffect::EntityEffect(Effect::Health(HealthChange { - amount: -50, - cause: HealthSource::Explosion { owner: *owner }, - })), + RadiusEffect::Entity( + None, + Effect::Health(HealthChange { + amount: -50, + cause: HealthSource::Explosion { owner: *owner }, + }), + ), RadiusEffect::TerrainDestruction(4.0), ], radius: 12.0,