diff --git a/client/src/lib.rs b/client/src/lib.rs index f8001fa101..d9038df8da 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -294,14 +294,6 @@ impl Client { .ecs_mut() .write_storage::<comp::Jumping>() .remove(self.entity); - self.state - .ecs_mut() - .write_storage::<comp::Dying>() - .remove(self.entity); - self.state - .ecs_mut() - .write_storage::<comp::Respawning>() - .remove(self.entity); self.tick += 1; Ok(frontend_events) diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index f5a7494bb2..08a0559f4d 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -19,10 +19,12 @@ impl Health { pub struct Stats { pub hp: Health, pub xp: u32, + pub is_dead: bool, } impl Stats { - pub fn is_dead(&self) -> bool { + pub fn should_die(&self) -> bool { + // TODO: Remove self.hp.current == 0 } } @@ -36,6 +38,7 @@ impl Default for Stats { last_change: None, }, xp: 0, + is_dead: false, } } } diff --git a/common/src/state.rs b/common/src/state.rs index 61278edca3..66984551f5 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -103,21 +103,24 @@ impl State { ecs.register_synced::<comp::Actor>(); ecs.register_synced::<comp::Player>(); ecs.register_synced::<comp::Stats>(); - ecs.register_synced::<comp::Attacking>(); + ecs.register_synced::<comp::Attacking>(); // TODO: Don't send this to the client? ecs.register::<comp::phys::ForceUpdate>(); - // Register unsynced (or synced by other means) components. + // Register components synced by other means ecs.register::<comp::phys::Pos>(); ecs.register::<comp::phys::Vel>(); ecs.register::<comp::phys::Dir>(); ecs.register::<comp::AnimationInfo>(); - ecs.register::<comp::Attacking>(); + + // Register client-local components ecs.register::<comp::Control>(); ecs.register::<comp::Jumping>(); + + // Register server-local components + ecs.register::<comp::Agent>(); ecs.register::<comp::Respawning>(); ecs.register::<comp::Gliding>(); ecs.register::<comp::Dying>(); - ecs.register::<comp::Agent>(); ecs.register::<inventory::Inventory>(); // Register synced resources used by the ECS. diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs index 1f3c74abb3..0ed148a774 100644 --- a/common/src/sys/inputs.rs +++ b/common/src/sys/inputs.rs @@ -149,7 +149,7 @@ impl<'a> System<'a> for Sys { { // Check if it is a hit if entity != b - && !stat_b.is_dead() + && !stat_b.is_dead && pos.0.distance_squared(pos_b.0) < 50.0 && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 { diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index 96eacddb7a..5a37c23401 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -21,8 +21,10 @@ impl<'a> System<'a> for Sys { fn run(&mut self, (entities, dt, mut stats, mut dyings): Self::SystemData) { for (entity, mut stat) in (&entities, &mut stats).join() { - if stat.hp.current == 0 { + if stat.should_die() && !stat.is_dead { + // TODO: Replace is_dead with client states dyings.insert(entity, Dying); + stat.is_dead = true; } if let Some(change) = &mut stat.hp.last_change { change.1 += dt.0 as f64; diff --git a/server/src/lib.rs b/server/src/lib.rs index ca9e52afa2..1f7205c7dc 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -39,9 +39,16 @@ const CLIENT_TIMEOUT: f64 = 20.0; // Seconds const DEFAULT_WORLD_SEED: u32 = 1337; pub enum Event { - ClientConnected { entity: EcsEntity }, - ClientDisconnected { entity: EcsEntity }, - Chat { entity: EcsEntity, msg: String }, + ClientConnected { + entity: EcsEntity, + }, + ClientDisconnected { + entity: EcsEntity, + }, + Chat { + entity: Option<EcsEntity>, + msg: String, + }, } #[derive(Copy, Clone)] @@ -220,6 +227,12 @@ impl Server { client.force_state(ClientState::Dead); } else { self.state.ecs_mut().delete_entity_synced(entity); + continue; + } + + if let Some(player) = self.state.ecs().read_storage::<comp::Player>().get(entity) { + self.clients + .notify_registered(ServerMsg::Chat(format!("{} died", &player.alias))); } } @@ -316,8 +329,6 @@ impl Server { // Cleanup let ecs = self.state.ecs_mut(); for entity in ecs.entities().join() { - ecs.write_storage::<comp::Jumping>().remove(entity); - ecs.write_storage::<comp::Gliding>().remove(entity); ecs.write_storage::<comp::Dying>().remove(entity); ecs.write_storage::<comp::Respawning>().remove(entity); } @@ -415,7 +426,13 @@ impl Server { }, ClientMsg::Register { player } => match client.client_state { ClientState::Connected => { - Self::initialize_player(state, entity, client, player) + Self::initialize_player(state, entity, client, player); + if let Some(player) = + state.ecs().read_storage::<comp::Player>().get(entity) + { + new_chat_msgs + .push((None, format!("{} logged in", &player.alias))); + } } // Use RequestState instead (No need to send `player` again). _ => client.error_state(RequestStateError::Impossible), @@ -464,7 +481,7 @@ impl Server { ClientState::Registered | ClientState::Spectator | ClientState::Dead - | ClientState::Character => new_chat_msgs.push((entity, msg)), + | ClientState::Character => new_chat_msgs.push((Some(entity), msg)), ClientState::Pending => {} }, ClientMsg::PlayerAnimation(animation_info) => { @@ -507,7 +524,9 @@ impl Server { // Always possible. ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), ClientMsg::Pong => {} - ClientMsg::Disconnect => disconnect = true, + ClientMsg::Disconnect => { + disconnect = true; + } } } } else if state.get_time() - client.last_ping > CLIENT_TIMEOUT || // Timeout @@ -521,6 +540,9 @@ impl Server { } if disconnect { + if let Some(player) = state.ecs().read_storage::<comp::Player>().get(entity) { + new_chat_msgs.push((None, format!("{} disconnected", &player.alias))); + } disconnected_clients.push(entity); client.postbox.send_message(ServerMsg::Disconnect); true @@ -531,20 +553,23 @@ impl Server { // Handle new chat messages. for (entity, msg) in new_chat_msgs { - // Handle chat commands. - if msg.starts_with("/") && msg.len() > 1 { - let argv = String::from(&msg[1..]); - self.process_chat_cmd(entity, argv); + if let Some(entity) = entity { + // Handle chat commands. + if msg.starts_with("/") && msg.len() > 1 { + let argv = String::from(&msg[1..]); + self.process_chat_cmd(entity, argv); + } else { + self.clients.notify_registered(ServerMsg::Chat( + match self.state.ecs().read_storage::<comp::Player>().get(entity) { + Some(player) => format!("[{}] {}", &player.alias, msg), + None => format!("[<anon>] {}", msg), + }, + )); + } } else { - self.clients.notify_registered(ServerMsg::Chat( - match self.state.ecs().read_storage::<comp::Player>().get(entity) { - Some(player) => format!("[{}] {}", &player.alias, msg), - None => format!("[<anon>] {}", msg), - }, - )); - - frontend_events.push(Event::Chat { entity, msg }); + self.clients.notify_registered(ServerMsg::Chat(msg.clone())); } + frontend_events.push(Event::Chat { entity, msg }); } // Handle client disconnects. diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 954ed65235..5cacd0bb26 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -307,7 +307,7 @@ impl Hud { let mut health_back_id_walker = self.ids.health_bar_backs.walk(); for (pos, name) in (&entities, &pos, &actor, &stats, player.maybe()) .join() - .filter(|(entity, _, _, stats, _)| *entity != me && !stats.is_dead()) + .filter(|(entity, _, _, stats, _)| *entity != me && !stats.is_dead) .map(|(entity, pos, actor, _, player)| match actor { comp::Actor::Character { name: char_name, .. @@ -338,7 +338,7 @@ impl Hud { for (entity, pos, stats) in (&entities, &pos, &stats) .join() - .filter(|(entity, _, stats)| *entity != me && !stats.is_dead()) + .filter(|(entity, _, stats)| *entity != me && !stats.is_dead) { let back_id = health_back_id_walker.next( &mut self.ids.health_bar_backs, diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 2824511ae4..cb67afaa33 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -617,7 +617,7 @@ impl FigureMgr { ) .join() { - if stat.is_dead() { + if stat.is_dead { continue; }