From c80351f6ca71feeb9b6bad6a7cb7a2679b1a3aff Mon Sep 17 00:00:00 2001 From: timokoesters Date: Sat, 29 Jun 2019 19:49:51 +0200 Subject: [PATCH] Fix double roll bug --- client/src/lib.rs | 2 + common/src/comp/action_state.rs | 26 ++++++ common/src/comp/mod.rs | 2 + common/src/msg/ecs_packet.rs | 6 -- common/src/msg/server.rs | 1 + common/src/state.rs | 9 +- common/src/sys/action_state.rs | 60 +++++++++++++ common/src/sys/animation.rs | 36 +++----- common/src/sys/mod.rs | 11 ++- server/src/lib.rs | 145 +++++++++++++++++--------------- 10 files changed, 188 insertions(+), 110 deletions(-) create mode 100644 common/src/comp/action_state.rs create mode 100644 common/src/sys/action_state.rs diff --git a/client/src/lib.rs b/client/src/lib.rs index bc6a88b056..94bc446c61 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -374,11 +374,13 @@ impl Client { pos, vel, ori, + action_state, } => match self.state.ecs().entity_from_uid(entity) { Some(entity) => { self.state.write_component(entity, pos); self.state.write_component(entity, vel); self.state.write_component(entity, ori); + self.state.write_component(entity, action_state); } None => {} }, diff --git a/common/src/comp/action_state.rs b/common/src/comp/action_state.rs new file mode 100644 index 0000000000..7296e1031f --- /dev/null +++ b/common/src/comp/action_state.rs @@ -0,0 +1,26 @@ +use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct ActionState { + pub moving: bool, + pub on_ground: bool, + pub attacking: bool, + pub rolling: bool, + pub gliding: bool, +} + +impl Default for ActionState { + fn default() -> Self { + Self { + moving: false, + on_ground: false, + attacking: false, + rolling: false, + gliding: false, + } + } +} + +impl Component for ActionState { + type Storage = FlaggedStorage>; +} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 4f0b3a6477..d93cf4c579 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -7,6 +7,7 @@ mod inventory; mod phys; mod player; mod stats; +mod action_state; // Reexports pub use agent::Agent; @@ -18,3 +19,4 @@ pub use inventory::{item, Inventory}; pub use phys::{ForceUpdate, Ori, Pos, Vel}; pub use player::Player; pub use stats::{Dying, HealthSource, Stats}; +pub use action_state::ActionState; diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs index 841b0d5a8e..1c533cfd0e 100644 --- a/common/src/msg/ecs_packet.rs +++ b/common/src/msg/ecs_packet.rs @@ -23,9 +23,6 @@ sphynx::sum_type! { Actor(comp::Actor), Player(comp::Player), Stats(comp::Stats), - Attacking(comp::Attacking), - Rolling(comp::Rolling), - Gliding(comp::Gliding), } } // Automatically derive From for EcsCompPhantom @@ -39,9 +36,6 @@ sphynx::sum_type! { Actor(PhantomData), Player(PhantomData), Stats(PhantomData), - Attacking(PhantomData), - Rolling(PhantomData), - Gliding(PhantomData), } } impl sphynx::CompPacket for EcsCompPacket { diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 12898ed72d..0fadce7afa 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -35,6 +35,7 @@ pub enum ServerMsg { pos: comp::Pos, vel: comp::Vel, ori: comp::Ori, + action_state: comp::ActionState, }, TerrainChunkUpdate { key: Vec2, diff --git a/common/src/state.rs b/common/src/state.rs index 919c9009f8..fa25027980 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -102,9 +102,6 @@ impl State { ecs.register_synced::(); ecs.register_synced::(); ecs.register_synced::(); - ecs.register_synced::(); - ecs.register_synced::(); - ecs.register_synced::(); // Register components synced by other means ecs.register::(); @@ -112,10 +109,14 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); ecs.register::(); + ecs.register::(); + ecs.register::(); + ecs.register::(); + ecs.register::(); // Register client-local components + ecs.register::(); ecs.register::(); // Register server-local components diff --git a/common/src/sys/action_state.rs b/common/src/sys/action_state.rs new file mode 100644 index 0000000000..b3c97a1b15 --- /dev/null +++ b/common/src/sys/action_state.rs @@ -0,0 +1,60 @@ +use crate::{ + comp::{ + Animation, AnimationInfo, Attacking, ForceUpdate, Gliding, Jumping, OnGround, Ori, Pos, + Rolling, Vel, ActionState, + }, + state::DeltaTime, +}; +use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; + +/// This system will set the ActionState component as specified by other components +pub struct Sys; +impl<'a> System<'a> for Sys { + type SystemData = ( + Entities<'a>, + Read<'a, DeltaTime>, + ReadStorage<'a, Vel>, + ReadStorage<'a, OnGround>, + ReadStorage<'a, Jumping>, + ReadStorage<'a, Gliding>, + ReadStorage<'a, Attacking>, + ReadStorage<'a, Rolling>, + WriteStorage<'a, ActionState>, + ); + + fn run( + &mut self, + ( + entities, + dt, + velocities, + on_grounds, + jumpings, + glidings, + attackings, + rollings, + mut action_states, + ): Self::SystemData, + ) { + for (entity, vel, on_ground, jumping, gliding, attacking, rolling, mut action_state) in ( + &entities, + &velocities, + on_grounds.maybe(), + jumpings.maybe(), + glidings.maybe(), + attackings.maybe(), + rollings.maybe(), + &mut action_states, + ) + .join() + { + *action_state = ActionState { + on_ground: on_ground.is_some(), + moving: vel.0.magnitude_squared() > 10.0, + attacking: attacking.is_some(), + rolling: rolling.is_some(), + gliding: gliding.is_some(), + }; + } + } +} diff --git a/common/src/sys/animation.rs b/common/src/sys/animation.rs index 3412b49943..7af4953117 100644 --- a/common/src/sys/animation.rs +++ b/common/src/sys/animation.rs @@ -1,7 +1,6 @@ use crate::{ comp::{ - Animation, AnimationInfo, Attacking, ForceUpdate, Gliding, Jumping, OnGround, Ori, Pos, - Rolling, Vel, + Animation, AnimationInfo, ForceUpdate, ActionState }, state::DeltaTime, }; @@ -13,12 +12,7 @@ impl<'a> System<'a> for Sys { type SystemData = ( Entities<'a>, Read<'a, DeltaTime>, - ReadStorage<'a, Vel>, - ReadStorage<'a, OnGround>, - ReadStorage<'a, Jumping>, - ReadStorage<'a, Gliding>, - ReadStorage<'a, Attacking>, - ReadStorage<'a, Rolling>, + ReadStorage<'a, ActionState>, WriteStorage<'a, AnimationInfo>, ); @@ -27,23 +21,13 @@ impl<'a> System<'a> for Sys { ( entities, dt, - velocities, - on_grounds, - jumpings, - glidings, - attackings, - rollings, + action_states, mut animation_infos, ): Self::SystemData, ) { - for (entity, vel, on_ground, jumping, gliding, attacking, rolling, mut animation_info) in ( + for (entity, a, mut animation_info) in ( &entities, - &velocities, - on_grounds.maybe(), - jumpings.maybe(), - glidings.maybe(), - attackings.maybe(), - rollings.maybe(), + &action_states, &mut animation_infos, ) .join() @@ -56,11 +40,11 @@ impl<'a> System<'a> for Sys { } let animation = match ( - on_ground.is_some(), - vel.0.magnitude_squared() > 10.0, // Moving - attacking.is_some(), - gliding.is_some(), - rolling.is_some(), + a.on_ground, + a.moving, + a.attacking, + a.gliding, + a.rolling, ) { (_, _, true, true, _) => impossible_animation("Attack while gliding"), (_, _, true, _, true) => impossible_animation("Roll while attacking"), diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index 65b24f12fa..6bf0ddb162 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -4,6 +4,7 @@ pub mod combat; pub mod controller; pub mod phys; mod stats; +mod action_state; // External use specs::DispatcherBuilder; @@ -11,6 +12,7 @@ use specs::DispatcherBuilder; // System names const AGENT_SYS: &str = "agent_sys"; const CONTROLLER_SYS: &str = "controller_sys"; +const ACTION_STATE_SYS: &str = "action_state_sys"; const PHYS_SYS: &str = "phys_sys"; const COMBAT_SYS: &str = "combat_sys"; const ANIMATION_SYS: &str = "animation_sys"; @@ -18,9 +20,10 @@ const STATS_SYS: &str = "stats_sys"; pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); - dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[]); - dispatch_builder.add(phys::Sys, PHYS_SYS, &[]); - dispatch_builder.add(combat::Sys, COMBAT_SYS, &[]); - dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[]); + dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]); + dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS]); + dispatch_builder.add(action_state::Sys, ACTION_STATE_SYS, &[CONTROLLER_SYS, PHYS_SYS]); + dispatch_builder.add(combat::Sys, COMBAT_SYS, &[ACTION_STATE_SYS]); + dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[ACTION_STATE_SYS]); dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]); } diff --git a/server/src/lib.rs b/server/src/lib.rs index 51c712393a..4e46303d5d 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -166,6 +166,7 @@ impl Server { state.write_component(entity, comp::Pos(spawn_point)); state.write_component(entity, comp::Vel(Vec3::zero())); state.write_component(entity, comp::Ori(Vec3::unit_y())); + state.write_component(entity, comp::ActionState::default()); // Make sure physics are accepted. state.write_component(entity, comp::ForceUpdate); @@ -210,74 +211,6 @@ impl Server { // Tick the world self.world.tick(dt); - // Sync deaths. - let ecs = &self.state.ecs(); - let clients = &mut self.clients; - let todo_kill = (&ecs.entities(), &ecs.read_storage::()) - .join() - .map(|(entity, dying)| { - // Chat message - if let Some(player) = ecs.read_storage::().get(entity) { - let msg = if let comp::HealthSource::Attack { by } = dying.cause { - ecs.entity_from_uid(by.into()).and_then(|attacker| { - ecs.read_storage::() - .get(attacker) - .map(|attacker_alias| { - format!( - "{} was killed by {}", - &player.alias, &attacker_alias.alias - ) - }) - }) - } else { - None - } - .unwrap_or(format!("{} died", &player.alias)); - - clients.notify_registered(ServerMsg::Chat(msg)); - } - - entity - }) - .collect::>(); - - // Actually kill them - for entity in todo_kill { - if let Some(client) = self.clients.get_mut(&entity) { - self.state.write_component(entity, comp::Vel(Vec3::zero())); - self.state.write_component(entity, comp::ForceUpdate); - client.force_state(ClientState::Dead); - } else { - if let Err(err) = self.state.ecs_mut().delete_entity_synced(entity) { - warn!("Failed to delete client not found in kill list: {:?}", err); - } - continue; - } - } - - // Handle respawns - let todo_respawn = ( - &self.state.ecs().entities(), - &self.state.ecs().read_storage::(), - ) - .join() - .map(|(entity, _)| entity) - .collect::>(); - - for entity in todo_respawn { - if let Some(client) = self.clients.get_mut(&entity) { - client.allow_state(ClientState::Character); - self.state.write_component(entity, comp::Stats::default()); - self.state - .ecs_mut() - .write_storage::() - .get_mut(entity) - .map(|pos| pos.0.z += 100.0); - self.state.write_component(entity, comp::Vel(Vec3::zero())); - self.state.write_component(entity, comp::ForceUpdate); - } - } - // 5) Fetch any generated `TerrainChunk`s and insert them into the terrain. // Also, send the chunk data to anybody that is close by. if let Ok((key, chunk)) = self.chunk_rx.try_recv() { @@ -618,11 +551,12 @@ impl Server { state.write_component(entity, player); // Sync physics - for (&uid, &pos, &vel, &ori) in ( + for (&uid, &pos, &vel, &ori, &action_state) in ( &state.ecs().read_storage::(), &state.ecs().read_storage::(), &state.ecs().read_storage::(), &state.ecs().read_storage::(), + &state.ecs().read_storage::(), ) .join() { @@ -631,6 +565,7 @@ impl Server { pos, vel, ori, + action_state, }); } @@ -645,12 +580,13 @@ impl Server { .notify_registered(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package())); // Sync physics - for (entity, &uid, &pos, &vel, &ori, force_update) in ( + for (entity, &uid, &pos, &vel, &ori, &action_state, force_update) in ( &self.state.ecs().entities(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), + &self.state.ecs().read_storage::(), self.state.ecs().read_storage::().maybe(), ) .join() @@ -660,6 +596,7 @@ impl Server { pos, vel, ori, + action_state, }; let state = &self.state; @@ -694,6 +631,74 @@ impl Server { } } + // Sync deaths. + let ecs = &self.state.ecs(); + let clients = &mut self.clients; + let todo_kill = (&ecs.entities(), &ecs.read_storage::()) + .join() + .map(|(entity, dying)| { + // Chat message + if let Some(player) = ecs.read_storage::().get(entity) { + let msg = if let comp::HealthSource::Attack { by } = dying.cause { + ecs.entity_from_uid(by.into()).and_then(|attacker| { + ecs.read_storage::() + .get(attacker) + .map(|attacker_alias| { + format!( + "{} was killed by {}", + &player.alias, &attacker_alias.alias + ) + }) + }) + } else { + None + } + .unwrap_or(format!("{} died", &player.alias)); + + clients.notify_registered(ServerMsg::Chat(msg)); + } + + entity + }) + .collect::>(); + + // Actually kill them + for entity in todo_kill { + if let Some(client) = self.clients.get_mut(&entity) { + self.state.write_component(entity, comp::Vel(Vec3::zero())); + self.state.write_component(entity, comp::ForceUpdate); + client.force_state(ClientState::Dead); + } else { + if let Err(err) = self.state.ecs_mut().delete_entity_synced(entity) { + warn!("Failed to delete client not found in kill list: {:?}", err); + } + continue; + } + } + + // Handle respawns + let todo_respawn = ( + &self.state.ecs().entities(), + &self.state.ecs().read_storage::(), + ) + .join() + .map(|(entity, _)| entity) + .collect::>(); + + for entity in todo_respawn { + if let Some(client) = self.clients.get_mut(&entity) { + client.allow_state(ClientState::Character); + self.state.write_component(entity, comp::Stats::default()); + self.state + .ecs_mut() + .write_storage::() + .get_mut(entity) + .map(|pos| pos.0.z += 100.0); + self.state.write_component(entity, comp::Vel(Vec3::zero())); + self.state.write_component(entity, comp::ForceUpdate); + } + } + // Remove all force flags. self.state .ecs_mut()