diff --git a/client/src/lib.rs b/client/src/lib.rs index b2ea500e61..be69fc5279 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(label_break_value)] +#![feature(label_break_value, duration_float)] pub mod error; pub mod input; @@ -16,14 +16,13 @@ use common::{ msg::{ClientMsg, ClientState, ServerMsg}, net::PostBox, state::State, - terrain::TerrainChunk, }; -use specs::Builder; use std::{ collections::HashMap, net::SocketAddr, time::{Duration, Instant}, }; + use threadpool::ThreadPool; use vek::*; @@ -41,6 +40,9 @@ pub struct Client { last_ping: f64, pub postbox: PostBox, + last_server_ping: Instant, + last_ping_delta: f64, + tick: u64, state: State, entity: EcsEntity, @@ -81,6 +83,9 @@ impl Client { last_ping: state.get_time(), postbox, + last_server_ping: Instant::now(), + last_ping_delta: 0.0, + tick: 0, state, entity, @@ -138,6 +143,11 @@ impl Client { self.postbox.send_message(ClientMsg::Chat(msg)) } + #[allow(dead_code)] + pub fn get_ping_ms(&self) -> f64 { + self.last_ping_delta * 1000.0 + } + /// Execute a single client tick, handle input and update the game state by the given duration. #[allow(dead_code)] pub fn tick(&mut self, input: Input, dt: Duration) -> Result, Error> { @@ -249,6 +259,12 @@ impl Client { .retain(|_, created| now.duration_since(*created) < Duration::from_secs(10)); } + // send a ping to the server once every second + if Instant::now().duration_since(self.last_server_ping) > Duration::from_secs(1) { + self.postbox.send_message(ClientMsg::Ping); + self.last_server_ping = Instant::now(); + } + // Finish the tick, pass control back to the frontend (step 6). self.tick += 1; Ok(frontend_events) @@ -276,7 +292,11 @@ impl Client { ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad), ServerMsg::Shutdown => return Err(Error::ServerShutdown), ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong), - ServerMsg::Pong => {} + ServerMsg::Pong => { + self.last_ping_delta = Instant::now() + .duration_since(self.last_server_ping) + .as_secs_f64() + } ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)), ServerMsg::SetPlayerEntity(uid) => { self.entity = self.state.ecs().entity_from_uid(uid).unwrap() @@ -332,6 +352,7 @@ impl Client { } else if self.state.get_time() - self.last_ping > SERVER_TIMEOUT * 0.5 { // Try pinging the server if the timeout is nearing. self.postbox.send_message(ClientMsg::Ping); + self.last_server_ping = Instant::now(); } Ok(frontend_events) diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 70a9c216f8..f6cbaa7b73 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -48,6 +48,7 @@ widget_ids! { // Debug debug_bg, fps_counter, + ping, // Game Version version, @@ -247,7 +248,7 @@ impl Hud { } } - fn update_layout(&mut self, tps: f64, global_state: &GlobalState) -> Vec { + fn update_layout(&mut self, tps: f64, ping_ms: f64, global_state: &GlobalState) -> Vec { let mut events = Vec::new(); let ref mut ui_widgets = self.ui.set_widgets(); let version = env!("CARGO_PKG_VERSION"); @@ -272,6 +273,12 @@ impl Hud { .font_id(self.fonts.opensans) .font_size(14) .set(self.ids.fps_counter, ui_widgets); + Text::new(&format!("Ping: {:.1}ms", ping_ms)) + .color(TEXT_COLOR) + .down_from(self.ids.fps_counter, 5.0) + .font_id(self.fonts.opensans) + .font_size(14) + .set(self.ids.ping, ui_widgets); } // Add Bag-Space Button. @@ -566,11 +573,16 @@ impl Hud { handled } - pub fn maintain(&mut self, global_state: &mut GlobalState, tps: f64) -> Vec { + pub fn maintain( + &mut self, + global_state: &mut GlobalState, + tps: f64, + ping_ms: f64, + ) -> Vec { if let Some(maybe_id) = self.to_focus.take() { self.ui.focus_widget(maybe_id); } - let events = self.update_layout(tps, &global_state); + let events = self.update_layout(tps, ping_ms, &global_state); self.ui.maintain(&mut global_state.window.renderer_mut()); events } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 1fa492c173..b0d6239982 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -177,7 +177,11 @@ impl PlayState for SessionState { ); // Maintain the UI. - for event in self.hud.maintain(global_state, clock.get_tps()) { + for event in self.hud.maintain( + global_state, + clock.get_tps(), + self.client.borrow().get_ping_ms(), + ) { match event { HudEvent::SendMessage(msg) => { // TODO: Handle result