diff --git a/client/src/lib.rs b/client/src/lib.rs index 5750dd5f0b..f7c748ea6a 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -22,6 +22,7 @@ use common::{ group, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InventoryManip, InventoryUpdateEvent, }, + event::{EventBus, LocalEvent}, msg::{ validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, DisconnectReason, InviteAnswer, Notification, PlayerInfo, PlayerListUpdate, RegisterError, RequestStateError, @@ -1426,6 +1427,15 @@ impl Client { ServerMsg::Outcomes(outcomes) => { frontend_events.extend(outcomes.into_iter().map(Event::Outcome)) }, + ServerMsg::Knockback(force) => { + self.state + .ecs() + .read_resource::>() + .emit_now(LocalEvent::ApplyForce { + entity: self.entity, + force, + }); + }, } } } diff --git a/common/src/event.rs b/common/src/event.rs index 616fb5736a..c7568bdce7 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -56,6 +56,10 @@ pub enum ServerEvent { pos: Pos, ori: Ori, }, + Knockback { + entity: EcsEntity, + force: Vec3, + }, LandOnGround { entity: EcsEntity, vel: Vec3, diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 18d4ee6f27..ce86e46c73 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -254,6 +254,7 @@ pub enum ServerMsg { Notification(Notification), SetViewDistance(u32), Outcomes(Vec), + Knockback(Vec3), } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index f4f4352ecc..3909408419 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -154,7 +154,7 @@ impl<'a> System<'a> for Sys { } if attack.knockback != 0.0 { - local_emitter.emit(LocalEvent::ApplyForce { + server_emitter.emit(ServerEvent::Knockback { entity: b, force: attack.knockback * *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5), diff --git a/common/src/sys/shockwave.rs b/common/src/sys/shockwave.rs index f5f9244df1..81cef7662f 100644 --- a/common/src/sys/shockwave.rs +++ b/common/src/sys/shockwave.rs @@ -63,7 +63,7 @@ impl<'a> System<'a> for Sys { ): Self::SystemData, ) { let mut server_emitter = server_bus.emitter(); - let mut local_emitter = local_bus.emitter(); + let _local_emitter = local_bus.emitter(); let time = time.0; let dt = dt.0; @@ -211,13 +211,13 @@ impl<'a> System<'a> for Sys { } if shockwave.knockback != 0.0 { if shockwave.knockback < 0.0 { - local_emitter.emit(LocalEvent::ApplyForce { + server_emitter.emit(ServerEvent::Knockback { entity: b, force: shockwave.knockback * *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, -1.0)), 0.85), }); } else { - local_emitter.emit(LocalEvent::ApplyForce { + server_emitter.emit(ServerEvent::Knockback { entity: b, force: shockwave.knockback * *Dir::slerp(ori.0, Dir::new(Vec3::new(0.0, 0.0, 1.0)), 0.5), diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 88428fc3d7..37331df6b0 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -32,6 +32,19 @@ pub fn handle_damage(server: &Server, uid: Uid, change: HealthChange) { } } +pub fn handle_knockback(server: &Server, entity: EcsEntity, force: Vec3) { + let state = &server.state; + let ecs = state.ecs(); + let mut velocities = ecs.write_storage::(); + if let Some(vel) = velocities.get_mut(entity) { + vel.0 = force; + } + let mut clients = state.ecs().write_storage::(); + if let Some(client) = clients.get_mut(entity) { + client.notify(ServerMsg::Knockback(force)); + } +} + /// Handle an entity dying. If it is a player, it will send a message to all /// other players. If the entity that killed it had stats, then give it exp for /// the kill. Experience given is equal to the level of the entity that was diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index 63ded0012f..224abd1b4b 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -8,8 +8,8 @@ use entity_creation::{ handle_loaded_character_data, handle_shockwave, handle_shoot, }; use entity_manipulation::{ - handle_damage, handle_destroy, handle_explosion, handle_land_on_ground, handle_level_up, - handle_respawn, + handle_damage, handle_destroy, handle_explosion, handle_knockback, handle_land_on_ground, + handle_level_up, handle_respawn, }; use group_manip::handle_group; use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount}; @@ -75,6 +75,7 @@ impl Server { pos, ori, } => handle_shockwave(self, properties, pos, ori), + ServerEvent::Knockback { entity, force } => handle_knockback(&self, entity, force), ServerEvent::Damage { uid, change } => handle_damage(&self, uid, change), ServerEvent::Destroy { entity, cause } => handle_destroy(self, entity, cause), ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip), diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 2c523d992a..426274ef79 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -420,6 +420,7 @@ impl ParticleMgr { } } } + fn maintain_shockwave_particles(&mut self, scene_data: &SceneData) { let state = scene_data.state; let ecs = state.ecs();