From b9607ef405b975edb7206ed5039369c43c8133bf Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 17 Apr 2019 19:32:29 +0200 Subject: [PATCH 1/7] Fix #21 by checking animation history Former-commit-id: 5272d1d7aee73fc07edeb31d9f29238d19b7d229 --- client/src/lib.rs | 12 ++++++++---- common/src/comp/character.rs | 8 +++++++- common/src/comp/mod.rs | 1 + common/src/msg/client.rs | 2 +- common/src/msg/server.rs | 2 +- common/src/state.rs | 2 +- common/src/sys/control.rs | 24 ++++++++++++++++-------- server/src/lib.rs | 30 +++++++++++++++++++++++------- voxygen/src/scene/figure.rs | 6 +++--- 9 files changed, 61 insertions(+), 26 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 3e0eeaa217..291ec29fd8 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -168,8 +168,12 @@ impl Client { } // Update the server about the player's currently playing animation - if let Some(animation) = self.state.read_storage().get(self.player).cloned() { - self.postbox.send_message(ClientMsg::PlayerAnimation(animation)); + if let Some(animationHistory) = self.state.read_storage::().get(self.player).cloned() { + if let Some(last) = animationHistory.last { + if animationHistory.current != last { + self.postbox.send_message(ClientMsg::PlayerAnimation(animationHistory)); + } + } } // Request chunks from the server @@ -228,9 +232,9 @@ impl Client { }, None => {}, }, - ServerMsg::EntityAnimation { entity, animation } => match self.state.ecs().entity_from_uid(entity) { + ServerMsg::EntityAnimation { entity, animationHistory } => match self.state.ecs().entity_from_uid(entity) { Some(entity) => { - self.state.write_component(entity, animation); + self.state.write_component(entity, animationHistory); }, None => {}, }, diff --git a/common/src/comp/character.rs b/common/src/comp/character.rs index e34919236e..2ed29831f6 100644 --- a/common/src/comp/character.rs +++ b/common/src/comp/character.rs @@ -19,6 +19,12 @@ pub enum Gender { } #[derive(Copy, Clone, Debug, Serialize, Deserialize)] +pub struct AnimationHistory { + pub last: Option, + pub current: Animation, +} + +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Animation { Idle, Run, @@ -55,6 +61,6 @@ impl Component for Character { type Storage = FlaggedStorage>; } -impl Component for Animation { +impl Component for AnimationHistory { type Storage = FlaggedStorage>; } diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index c67f27cee2..d10012c976 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -7,4 +7,5 @@ pub mod phys; pub use agent::{Agent, Control}; pub use character::Character; pub use player::Player; +pub use character::AnimationHistory; pub use character::Animation; diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs index 01c35a7962..95eaadecbf 100644 --- a/common/src/msg/client.rs +++ b/common/src/msg/client.rs @@ -11,7 +11,7 @@ pub enum ClientMsg { Ping, Pong, Chat(String), - PlayerAnimation(comp::character::Animation), + PlayerAnimation(comp::character::AnimationHistory), PlayerPhysics { pos: comp::phys::Pos, vel: comp::phys::Vel, diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 1585c5f32f..4b5a1b5517 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -25,7 +25,7 @@ pub enum ServerMsg { }, EntityAnimation { entity: u64, - animation: comp::Animation, + animationHistory: comp::AnimationHistory, }, TerrainChunkUpdate { key: Vec3, diff --git a/common/src/state.rs b/common/src/state.rs index 84a6736362..6a12cc6d7d 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -100,7 +100,7 @@ impl State { ecs.internal_mut().register::(); ecs.internal_mut().register::(); ecs.internal_mut().register::(); - ecs.internal_mut().register::(); + ecs.internal_mut().register::(); ecs.internal_mut().register::(); ecs.internal_mut().register::(); diff --git a/common/src/sys/control.rs b/common/src/sys/control.rs index a590e13c47..9179ea744a 100644 --- a/common/src/sys/control.rs +++ b/common/src/sys/control.rs @@ -3,7 +3,7 @@ use specs::{Join, Read, ReadStorage, System, WriteStorage, Entities}; use vek::*; // Crate -use crate::comp::{Control, Animation, phys::{Pos, Vel, Dir}}; +use crate::comp::{Control, Animation, AnimationHistory, phys::{Pos, Vel, Dir}}; // Basic ECS AI agent system pub struct Sys; @@ -13,7 +13,7 @@ impl<'a> System<'a> for Sys { Entities<'a>, WriteStorage<'a, Vel>, WriteStorage<'a, Dir>, - WriteStorage<'a, Animation>, + WriteStorage<'a, AnimationHistory>, ReadStorage<'a, Control>, ); @@ -23,12 +23,20 @@ impl<'a> System<'a> for Sys { // Apply physics to the player: acceleration and non-linear decceleration vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03; - if control.move_dir.magnitude() > 0.01 { - dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0); - anims.insert(entity, Animation::Run); - } else { - anims.insert(entity, Animation::Idle); - } + let animation = + if control.move_dir.magnitude() > 0.01 { + dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0); + Animation::Run + } else { + Animation::Idle + }; + + let lastAnimation = anims.get_mut(entity).map(|h| h.current); + + anims.insert(entity, AnimationHistory { + last: lastAnimation, + current: animation, + }); } } } diff --git a/server/src/lib.rs b/server/src/lib.rs index 0eb84959b5..ba7dd7ec8e 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -266,7 +266,7 @@ impl Server { ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), ClientMsg::Pong => {} ClientMsg::Chat(msg) => new_chat_msgs.push((entity, msg)), - ClientMsg::PlayerAnimation(animation) => state.write_component(entity, animation), + ClientMsg::PlayerAnimation(animationHistory) => state.write_component(entity, animationHistory), ClientMsg::PlayerPhysics { pos, vel, dir } => { state.write_component(entity, pos); state.write_component(entity, vel); @@ -369,15 +369,31 @@ impl Server { } // Sync animation states - for (entity, &uid, &animation) in ( + for (entity, &uid, &animationHistory) in ( &self.state.ecs().internal().entities(), &self.state.ecs().internal().read_storage::(), - &self.state.ecs().internal().read_storage::(), + &self.state.ecs().internal().read_storage::(), ).join() { - self.clients.notify_connected_except(entity, ServerMsg::EntityAnimation { - entity: uid.into(), - animation, - }); + if let Some(last) = animationHistory.last { + if animationHistory.current == last { + continue; + } + + self.clients.notify_connected_except(entity, ServerMsg::EntityAnimation { + entity: uid.into(), + animationHistory, + }); + } + } + + // Update animation last/current state + for (entity, mut animationHistory) in ( + &self.state.ecs().internal().entities(), + &mut self.state.ecs().internal().write_storage::() + ).join() { + animationHistory.last = None; + let mut new = animationHistory.clone(); + new.last = Some(new.current); } // Remove all force flags diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 75b727b07f..02089eb724 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -83,18 +83,18 @@ impl Figures { pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) { let time = client.state().get_time(); let ecs = client.state_mut().ecs_mut().internal_mut(); - for (entity, pos, dir, character, animation) in ( + for (entity, pos, dir, character, animationHistory) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), - &ecs.read_storage::(), + &ecs.read_storage::(), ).join() { let state = self.states .entry(entity) .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); - let target_skeleton = match animation { + let target_skeleton = match animationHistory.current { comp::character::Animation::Idle => IdleAnimation::update_skeleton(&mut state.skeleton, time), comp::character::Animation::Run => RunAnimation::update_skeleton(&mut state.skeleton, time), }; From abf32d622955bedf685475a1e8a9ce7fb0896651 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 17 Apr 2019 19:41:20 +0200 Subject: [PATCH 2/7] Add comments Former-commit-id: 950c811256b8c20f58e4bb3c998acc746c4b929d --- client/src/lib.rs | 2 +- server/src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 291ec29fd8..b2ad5904d5 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -167,7 +167,7 @@ impl Client { _ => {}, } - // Update the server about the player's currently playing animation + // Update the server about the player's currently playing animation and the previous one if let Some(animationHistory) = self.state.read_storage::().get(self.player).cloned() { if let Some(last) = animationHistory.last { if animationHistory.current != last { diff --git a/server/src/lib.rs b/server/src/lib.rs index ba7dd7ec8e..fd1e8fad5e 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -375,6 +375,7 @@ impl Server { &self.state.ecs().internal().read_storage::(), ).join() { if let Some(last) = animationHistory.last { + // Check if we need to sync if animationHistory.current == last { continue; } From 5044fe8cb59f4d9532ab18ab1aeb807de95e7bb0 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 17 Apr 2019 20:06:06 +0200 Subject: [PATCH 3/7] Simplify code Former-commit-id: c8bdf4199c913ab43ba08fdb19384bf7fcc6653d --- client/src/lib.rs | 6 ++---- server/src/lib.rs | 22 +++++++++------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index b2ad5904d5..53d47a7084 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -169,10 +169,8 @@ impl Client { // Update the server about the player's currently playing animation and the previous one if let Some(animationHistory) = self.state.read_storage::().get(self.player).cloned() { - if let Some(last) = animationHistory.last { - if animationHistory.current != last { - self.postbox.send_message(ClientMsg::PlayerAnimation(animationHistory)); - } + if Some(animationHistory.current) != animationHistory.last { + self.postbox.send_message(ClientMsg::PlayerAnimation(animationHistory)); } } diff --git a/server/src/lib.rs b/server/src/lib.rs index fd1e8fad5e..7f902f24d1 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -374,17 +374,15 @@ impl Server { &self.state.ecs().internal().read_storage::(), &self.state.ecs().internal().read_storage::(), ).join() { - if let Some(last) = animationHistory.last { - // Check if we need to sync - if animationHistory.current == last { - continue; - } - - self.clients.notify_connected_except(entity, ServerMsg::EntityAnimation { - entity: uid.into(), - animationHistory, - }); + // Check if we need to sync + if Some(animationHistory.current) == animationHistory.last { + continue; } + + self.clients.notify_connected_except(entity, ServerMsg::EntityAnimation { + entity: uid.into(), + animationHistory, + }); } // Update animation last/current state @@ -392,9 +390,7 @@ impl Server { &self.state.ecs().internal().entities(), &mut self.state.ecs().internal().write_storage::() ).join() { - animationHistory.last = None; - let mut new = animationHistory.clone(); - new.last = Some(new.current); + animationHistory.last = Some(animationHistory.current); } // Remove all force flags From 7e3f271838cebaf845f6f57bd78585a153f0746a Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 17 Apr 2019 21:22:34 +0200 Subject: [PATCH 4/7] Move code for initializing clients to new function Former-commit-id: 55f8a9b49599b6912489c597c47a13d7657f78f1 --- server/src/lib.rs | 69 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index 7f902f24d1..ebd76783a5 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -15,6 +15,7 @@ use common::{ net::PostOffice, state::{State, Uid}, terrain::TerrainChunk, + comp::character::Animation, }; use specs::{ join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder, @@ -235,28 +236,7 @@ impl Server { match client.state { ClientState::Connecting => match msg { ClientMsg::Connect { player, character } => { - - // Write client components - state.write_component(entity, player); - state.write_component(entity, comp::phys::Pos(Vec3::zero())); - state.write_component(entity, comp::phys::Vel(Vec3::zero())); - state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); - if let Some(character) = character { - state.write_component(entity, character); - } - state.write_component(entity, comp::phys::ForceUpdate); - - client.state = ClientState::Connected; - - // Return a handshake with the state of the current world - client.notify(ServerMsg::Handshake { - ecs_state: state.ecs().gen_state_package(), - player_entity: state - .ecs() - .uid_from_entity(entity) - .unwrap() - .into(), - }); + Self::initialize_client(state, entity, client, player, character); } _ => disconnect = true, }, @@ -341,6 +321,51 @@ impl Server { Ok(frontend_events) } + /// Initialize a new client states with important information + fn initialize_client( + state: &mut State, + entity: specs::Entity, + client: &mut Client, + player: comp::Player, + character: Option, + ) { + // Save player metadata (for example the username) + state.write_component(entity, player); + + // Give the player it's character if he wants one + // (Chat only clients don't need one for example) + if let Some(character) = character { + state.write_component(entity, character); + + // Every character has to have these components + state.write_component(entity, comp::phys::Pos(Vec3::zero())); + state.write_component(entity, comp::phys::Vel(Vec3::zero())); + state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); + // Make sure everything is accepted + state.write_component(entity, comp::phys::ForceUpdate); + + // Set initial animation + state.write_component(entity, comp::AnimationHistory { + last: None, + current: Animation::Idle + }); + } + + client.state = ClientState::Connected; + + // Return a handshake with the state of the current world + // (All components Sphynx tracks) + client.notify(ServerMsg::Handshake { + ecs_state: state.ecs().gen_state_package(), + player_entity: state + .ecs() + .uid_from_entity(entity) + .unwrap() + .into(), + }); + + } + /// Sync client states with the most up to date information fn sync_clients(&mut self) { // Sync 'logical' state using Sphynx From 61578b238edf6fe2f7576d61cb906473f20b2305 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 17 Apr 2019 22:26:11 +0200 Subject: [PATCH 5/7] Sync animation states on initial connection Former-commit-id: 4ed67b6cbf56fceb03fa6a66b25b78925b91fc8a --- server/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/server/src/lib.rs b/server/src/lib.rs index ebd76783a5..305667195b 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -364,6 +364,18 @@ impl Server { .into(), }); + // Sync logical information other players have authority over, not the server + for (other_entity, &uid, &animationHistory) in ( + &state.ecs().internal().entities(), + &state.ecs().internal().read_storage::(), + &state.ecs().internal().read_storage::(), + ).join() { + // AnimationHistory + client.postbox.send_message(ServerMsg::EntityAnimation { + entity: uid.into(), + animationHistory: animationHistory, + }); + } } /// Sync client states with the most up to date information From ec161531640d37aa85e35c2770f333cb2c628fdf Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 17 Apr 2019 22:32:36 +0200 Subject: [PATCH 6/7] Rename animationHistory to animation_history Former-commit-id: bb2c882332fa9c3fd7f2c7fbd6143cd5f85153d8 --- client/src/lib.rs | 10 +++++----- common/src/msg/server.rs | 2 +- server/src/lib.rs | 16 ++++++++-------- voxygen/src/scene/figure.rs | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 53d47a7084..4931912b66 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -168,9 +168,9 @@ impl Client { } // Update the server about the player's currently playing animation and the previous one - if let Some(animationHistory) = self.state.read_storage::().get(self.player).cloned() { - if Some(animationHistory.current) != animationHistory.last { - self.postbox.send_message(ClientMsg::PlayerAnimation(animationHistory)); + if let Some(animation_history) = self.state.read_storage::().get(self.player).cloned() { + if Some(animation_history.current) != animation_history.last { + self.postbox.send_message(ClientMsg::PlayerAnimation(animation_history)); } } @@ -230,9 +230,9 @@ impl Client { }, None => {}, }, - ServerMsg::EntityAnimation { entity, animationHistory } => match self.state.ecs().entity_from_uid(entity) { + ServerMsg::EntityAnimation { entity, animation_history } => match self.state.ecs().entity_from_uid(entity) { Some(entity) => { - self.state.write_component(entity, animationHistory); + self.state.write_component(entity, animation_history); }, None => {}, }, diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 4b5a1b5517..3372b524fb 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -25,7 +25,7 @@ pub enum ServerMsg { }, EntityAnimation { entity: u64, - animationHistory: comp::AnimationHistory, + animation_history: comp::AnimationHistory, }, TerrainChunkUpdate { key: Vec3, diff --git a/server/src/lib.rs b/server/src/lib.rs index 305667195b..fa9a390eb7 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -246,7 +246,7 @@ impl Server { ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), ClientMsg::Pong => {} ClientMsg::Chat(msg) => new_chat_msgs.push((entity, msg)), - ClientMsg::PlayerAnimation(animationHistory) => state.write_component(entity, animationHistory), + ClientMsg::PlayerAnimation(animation_history) => state.write_component(entity, animation_history), ClientMsg::PlayerPhysics { pos, vel, dir } => { state.write_component(entity, pos); state.write_component(entity, vel); @@ -365,7 +365,7 @@ impl Server { }); // Sync logical information other players have authority over, not the server - for (other_entity, &uid, &animationHistory) in ( + for (other_entity, &uid, &animation_history) in ( &state.ecs().internal().entities(), &state.ecs().internal().read_storage::(), &state.ecs().internal().read_storage::(), @@ -373,7 +373,7 @@ impl Server { // AnimationHistory client.postbox.send_message(ServerMsg::EntityAnimation { entity: uid.into(), - animationHistory: animationHistory, + animation_history: animation_history, }); } } @@ -406,28 +406,28 @@ impl Server { } // Sync animation states - for (entity, &uid, &animationHistory) in ( + for (entity, &uid, &animation_history) in ( &self.state.ecs().internal().entities(), &self.state.ecs().internal().read_storage::(), &self.state.ecs().internal().read_storage::(), ).join() { // Check if we need to sync - if Some(animationHistory.current) == animationHistory.last { + if Some(animation_history.current) == animation_history.last { continue; } self.clients.notify_connected_except(entity, ServerMsg::EntityAnimation { entity: uid.into(), - animationHistory, + animation_history, }); } // Update animation last/current state - for (entity, mut animationHistory) in ( + for (entity, mut animation_history) in ( &self.state.ecs().internal().entities(), &mut self.state.ecs().internal().write_storage::() ).join() { - animationHistory.last = Some(animationHistory.current); + animation_history.last = Some(animation_history.current); } // Remove all force flags diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 02089eb724..66f1a65b27 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -83,7 +83,7 @@ impl Figures { pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) { let time = client.state().get_time(); let ecs = client.state_mut().ecs_mut().internal_mut(); - for (entity, pos, dir, character, animationHistory) in ( + for (entity, pos, dir, character, animation_history) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), @@ -94,7 +94,7 @@ impl Figures { .entry(entity) .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); - let target_skeleton = match animationHistory.current { + let target_skeleton = match animation_history.current { comp::character::Animation::Idle => IdleAnimation::update_skeleton(&mut state.skeleton, time), comp::character::Animation::Run => RunAnimation::update_skeleton(&mut state.skeleton, time), }; From 86898c26a0fca3c767078c09b5d70272d819c657 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 17 Apr 2019 22:44:10 +0200 Subject: [PATCH 7/7] Rename lastAnimation to last_animation Former-commit-id: 7eabea72ad5ee2cfed20b3927a828eb55fae8e33 --- common/src/sys/control.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/sys/control.rs b/common/src/sys/control.rs index 9179ea744a..b2568c6975 100644 --- a/common/src/sys/control.rs +++ b/common/src/sys/control.rs @@ -31,10 +31,10 @@ impl<'a> System<'a> for Sys { Animation::Idle }; - let lastAnimation = anims.get_mut(entity).map(|h| h.current); + let last_animation = anims.get_mut(entity).map(|h| h.current); anims.insert(entity, AnimationHistory { - last: lastAnimation, + last: last_animation, current: animation, }); }