diff --git a/server/src/lib.rs b/server/src/lib.rs index 1639fd323c..dc199ff337 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -764,13 +764,14 @@ impl Server { // 3) Handle inputs from clients frontend_events.append(&mut self.handle_new_connections()?); - // Handle game events - frontend_events.append(&mut self.handle_events()); - let before_tick_4 = Instant::now(); // 4) Tick the client's LocalState. self.state.tick(dt, sys::add_server_systems); + let before_handle_events = Instant::now(); + // Handle game events + frontend_events.append(&mut self.handle_events()); + // Tick the world self.world.tick(dt); @@ -834,7 +835,11 @@ impl Server { self.metrics .tick_time .with_label_values(&["state tick"]) - .set((before_tick_6 - before_tick_4).as_nanos() as i64 - total_sys_nanos); + .set((before_handle_events - before_tick_4).as_nanos() as i64 - total_sys_nanos); + self.metrics + .tick_time + .with_label_values(&["handle server events"]) + .set((before_tick_6 - before_handle_events).as_nanos() as i64); self.metrics .tick_time .with_label_values(&["sphynx sync"]) diff --git a/server/src/sys/entity_sync.rs b/server/src/sys/entity_sync.rs index 22cb515fd6..97d2663779 100644 --- a/server/src/sys/entity_sync.rs +++ b/server/src/sys/entity_sync.rs @@ -90,15 +90,47 @@ impl<'a> System<'a> for Sys { for event in region.events() { match event { - RegionEvent::Entered(_, _) => {} // TODO use this + RegionEvent::Entered(id, maybe_key) => { + let entity = entities.entity(*id); + if let Some((uid, pos, vel, ori, character_state)) = + uids.get(entity).and_then(|uid| { + positions.get(entity).map(|pos| { + ( + uid, + pos, + velocities.get(entity), + orientations.get(entity), + character_states.get(entity), + ) + }) + }) + { + for (client, regions, _, _) in &mut subscribers { + if maybe_key + .as_ref() + .map(|key| !regions.contains(key)) + .unwrap_or(true) + { + send_initial_unsynced_components( + client, + uid, + pos, + vel, + ori, + character_state, + ); + } + } + } + } RegionEvent::Left(id, maybe_key) => { // Lookup UID for entity if let Some(&uid) = uids.get(entities.entity(*id)) { for (client, regions, _, _) in &mut subscribers { - if !maybe_key + if maybe_key .as_ref() - .map(|key| regions.contains(key)) - .unwrap_or(false) + .map(|key| !regions.contains(key)) + .unwrap_or(true) { client.notify(ServerMsg::DeleteEntity(uid.into())); } @@ -117,6 +149,8 @@ impl<'a> System<'a> for Sys { let distance_sq = client_pos.0.distance_squared(pos.0); // Throttle update rate based on distance to player + // TODO: more entities will be farther away so it could be more + // efficient to reverse the order of these checks let update = if !throttle || distance_sq < 100.0f32.powi(2) { true // Closer than 100.0 blocks } else if distance_sq < 150.0f32.powi(2) { @@ -151,6 +185,8 @@ impl<'a> System<'a> for Sys { ) .join() { + // TODO: An entity that stoppped moving on a tick that it wasn't sent to the player + // will never have it's position updated if last_pos.get(entity).map(|&l| l.0 != pos).unwrap_or(true) { let _ = last_pos.insert(entity, Last(pos)); send_msg( @@ -231,3 +267,27 @@ impl<'a> System<'a> for Sys { timer.end(); } } + +pub fn send_initial_unsynced_components( + client: &mut Client, + uid: &Uid, + pos: &Pos, + vel: Option<&Vel>, + ori: Option<&Ori>, + character_state: Option<&CharacterState>, +) { + let entity = (*uid).into(); + client.notify(ServerMsg::EntityPos { entity, pos: *pos }); + if let Some(&vel) = vel { + client.notify(ServerMsg::EntityVel { entity, vel }); + } + if let Some(&ori) = ori { + client.notify(ServerMsg::EntityOri { entity, ori }); + } + if let Some(&character_state) = character_state { + client.notify(ServerMsg::EntityCharacterState { + entity, + character_state, + }); + } +} diff --git a/server/src/sys/subscription.rs b/server/src/sys/subscription.rs index cdc51f8ab9..9f41460e90 100644 --- a/server/src/sys/subscription.rs +++ b/server/src/sys/subscription.rs @@ -1,7 +1,7 @@ use super::SysTimer; use crate::client::{self, Client, RegionSubscription}; use common::{ - comp::{Player, Pos}, + comp::{CharacterState, Ori, Player, Pos, Vel}, msg::ServerMsg, region::{region_in_vd, regions_in_vd, Event as RegionEvent, RegionMap}, state::Uid, @@ -20,6 +20,9 @@ impl<'a> System<'a> for Sys { Write<'a, SysTimer>, ReadStorage<'a, Uid>, ReadStorage<'a, Pos>, + ReadStorage<'a, Vel>, + ReadStorage<'a, Ori>, + ReadStorage<'a, CharacterState>, ReadStorage<'a, Player>, WriteStorage<'a, Client>, WriteStorage<'a, RegionSubscription>, @@ -27,7 +30,19 @@ impl<'a> System<'a> for Sys { fn run( &mut self, - (entities, region_map, mut timer, uids, positions, players, mut clients, mut subscriptions): Self::SystemData, + ( + entities, + region_map, + mut timer, + uids, + positions, + velocities, + orientations, + character_states, + players, + mut clients, + mut subscriptions, + ): Self::SystemData, ) { timer.start(); @@ -119,8 +134,29 @@ impl<'a> System<'a> for Sys { (vd as f32 * chunk_size) + (client::CHUNK_FUZZ as f32 + chunk_size) * 2.0f32.sqrt(), ) { + // Send client intial info about the entities in this region if subscription.regions.insert(key) { - // TODO: send the client initial infromation for all the entities in this region + if let Some(region) = region_map.get(key) { + for (uid, pos, vel, ori, character_state, _) in ( + &uids, + &positions, + velocities.maybe(), + orientations.maybe(), + character_states.maybe(), + region.entities(), + ) + .join() + { + super::entity_sync::send_initial_unsynced_components( + client, + uid, + pos, + vel, + ori, + character_state, + ); + } + } } } }