From 99e64d06b9ca4eadf8959773ec21537b92bba348 Mon Sep 17 00:00:00 2001 From: Capucho Date: Sat, 7 Mar 2020 22:14:21 +0000 Subject: [PATCH 1/4] Janky fix of the logout timeout problem --- client/src/lib.rs | 3 ++- common/src/msg/mod.rs | 1 + server/src/sys/message.rs | 7 +++++++ voxygen/src/session.rs | 31 +++++++++++++++++++++++-------- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 5bb2068dc6..6a7239e606 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -197,7 +197,7 @@ impl Client { /// Send disconnect message to the server pub fn request_logout(&mut self) { self.postbox.send_message(ClientMsg::Disconnect); - self.client_state = ClientState::Pending; + self.client_state = ClientState::Disconnected; } /// Request a state transition to `ClientState::Registered` from an ingame @@ -703,6 +703,7 @@ impl Client { }, ServerMsg::Disconnect => { frontend_events.push(Event::Disconnect); + self.client_state = ClientState::Disconnected; }, } } diff --git a/common/src/msg/mod.rs b/common/src/msg/mod.rs index 1baee67e15..411763607f 100644 --- a/common/src/msg/mod.rs +++ b/common/src/msg/mod.rs @@ -16,6 +16,7 @@ pub enum ClientState { Registered, Spectator, Character, + Disconnected, } pub const MAX_BYTES_CHAT_MSG: usize = 256; diff --git a/server/src/sys/message.rs b/server/src/sys/message.rs index f68d32f9e6..6fbf50e840 100644 --- a/server/src/sys/message.rs +++ b/server/src/sys/message.rs @@ -111,6 +111,7 @@ impl<'a> System<'a> for Sys { server_emitter.emit(ServerEvent::ExitIngame { entity }); }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, // Request spectator state ClientMsg::Spectate => match client.client_state { @@ -121,6 +122,7 @@ impl<'a> System<'a> for Sys { client.allow_state(ClientState::Spectator) }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, // Valid player ClientMsg::Register { player, password } if player.is_valid() => { @@ -187,6 +189,7 @@ impl<'a> System<'a> for Sys { }, ClientState::Character => client.error_state(RequestStateError::Already), ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, ClientMsg::ControllerInputs(inputs) => match client.client_state { ClientState::Connected @@ -200,6 +203,7 @@ impl<'a> System<'a> for Sys { } }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, ClientMsg::ControlEvent(event) => match client.client_state { ClientState::Connected @@ -213,6 +217,7 @@ impl<'a> System<'a> for Sys { } }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, ClientMsg::ChatMsg { message } => match client.client_state { ClientState::Connected => client.error_state(RequestStateError::Impossible), @@ -227,6 +232,7 @@ impl<'a> System<'a> for Sys { ), }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, ClientMsg::PlayerPhysics { pos, vel, ori } => match client.client_state { ClientState::Character => { @@ -267,6 +273,7 @@ impl<'a> System<'a> for Sys { } }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, // Always possible. ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index cf47210669..234db82d4f 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -33,6 +33,14 @@ pub struct SessionState { selected_block: Block, } +/// The action to perform after a tick +enum TickAction { + // Continue executing + Continue, + // Disconnected (i.e. go to main menu) + Disconnect, +} + /// Represents an active game session (i.e., the one being played). impl SessionState { /// Create a new `SessionState`. @@ -65,7 +73,7 @@ impl SessionState { impl SessionState { /// Tick the session (and the client attached to it). - fn tick(&mut self, dt: Duration) -> Result<(), Error> { + fn tick(&mut self, dt: Duration) -> Result { self.inputs.tick(dt); for event in self.client.borrow_mut().tick( self.inputs.clone(), @@ -79,7 +87,10 @@ impl SessionState { } => { self.hud.new_message(event); }, - client::Event::Disconnect => {}, // TODO + client::Event::Disconnect => { + log::warn!("disconnect"); + return Ok(TickAction::Disconnect); + }, client::Event::DisconnectionNotification(time) => { let message = match time { 0 => String::from("Goodbye!"), @@ -94,7 +105,7 @@ impl SessionState { } } - Ok(()) + Ok(TickAction::Continue) } /// Clean up the session (and the client attached to it) after a tick. @@ -390,12 +401,16 @@ impl PlayState for SessionState { || !global_state.singleplayer.as_ref().unwrap().is_paused() { // Perform an in-game tick. - if let Err(err) = self.tick(clock.get_avg_delta()) { - global_state.info_message = - Some(localized_strings.get("common.connection_lost").to_owned()); - error!("[session] Failed to tick the scene: {:?}", err); + match self.tick(clock.get_avg_delta()) { + Ok(TickAction::Continue) => {}, // Do nothing + Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu + Err(err) => { + global_state.info_message = + Some(localized_strings.get("common.connection_lost").to_owned()); + error!("[session] Failed to tick the scene: {:?}", err); - return PlayStateResult::Pop; + return PlayStateResult::Pop; + }, } } From ca6d5ab506330890c5d809b16f3a914d633f60be Mon Sep 17 00:00:00 2001 From: Capucho Date: Sun, 8 Mar 2020 08:06:22 +0000 Subject: [PATCH 2/4] Proper fix to the logout timeout problem using Disconnect ACK --- client/src/lib.rs | 10 +++++++++- common/src/msg/client.rs | 1 + server/src/sys/message.rs | 4 +++- voxygen/src/menu/char_selection/mod.rs | 7 ++++++- voxygen/src/session.rs | 21 +++++++++------------ 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 6a7239e606..c44c787e6b 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -77,6 +77,8 @@ pub struct Client { loaded_distance: f32, pending_chunks: HashMap, Instant>, + + disconnected: bool, } impl Client { @@ -163,6 +165,8 @@ impl Client { loaded_distance: 0.0, pending_chunks: HashMap::new(), + + disconnected: false, }) } @@ -702,8 +706,9 @@ impl Client { ); }, ServerMsg::Disconnect => { + self.disconnected = true; frontend_events.push(Event::Disconnect); - self.client_state = ClientState::Disconnected; + self.postbox.send_message(ClientMsg::Terminate); }, } } @@ -716,6 +721,9 @@ impl Client { Ok(frontend_events) } + // Get's whether or not the client just disconnected + pub fn disconnected(&self) -> bool { self.disconnected } + /// Get the player's entity. pub fn entity(&self) -> EcsEntity { self.entity } diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs index b4022483ad..4ef051ef60 100644 --- a/common/src/msg/client.rs +++ b/common/src/msg/client.rs @@ -35,4 +35,5 @@ pub enum ClientMsg { key: Vec2, }, Disconnect, + Terminate, } diff --git a/server/src/sys/message.rs b/server/src/sys/message.rs index 6fbf50e840..b040b20a2d 100644 --- a/server/src/sys/message.rs +++ b/server/src/sys/message.rs @@ -281,6 +281,9 @@ impl<'a> System<'a> for Sys { ClientMsg::Disconnect => { disconnect = true; }, + ClientMsg::Terminate => { + server_emitter.emit(ServerEvent::ClientDisconnect(entity)); + }, } } @@ -295,7 +298,6 @@ impl<'a> System<'a> for Sys { ServerMsg::broadcast(format!("{} went offline.", &player.alias)), )); } - server_emitter.emit(ServerEvent::ClientDisconnect(entity)); client.postbox.send_message(ServerMsg::Disconnect); } } diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index f7eaae27c2..0931126e37 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -39,6 +39,11 @@ impl PlayState for CharSelectionState { // Set up an fps clock. let mut clock = Clock::start(); + // Check if we just disconnected, if so go to main menu + if self.client.borrow().disconnected() { + return PlayStateResult::Pop; + } + let mut current_client_state = self.client.borrow().get_client_state(); while let ClientState::Pending | ClientState::Registered = current_client_state { // Handle window events @@ -141,7 +146,7 @@ impl PlayState for CharSelectionState { ) { global_state.info_message = Some(localized_strings.get("common.connection_lost").to_owned()); - error!("[session] Failed to tick the scene: {:?}", err); + error!("[char_selection] Failed to tick the scene: {:?}", err); return PlayStateResult::Pop; } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 234db82d4f..7e36d44543 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -24,6 +24,14 @@ use specs::{Join, WorldExt}; use std::{cell::RefCell, rc::Rc, time::Duration}; use vek::*; +/// The action to perform after a tick +enum TickAction { + // Continue executing + Continue, + // Disconnected (i.e. go to main menu) + Disconnect, +} + pub struct SessionState { scene: Scene, client: Rc>, @@ -33,14 +41,6 @@ pub struct SessionState { selected_block: Block, } -/// The action to perform after a tick -enum TickAction { - // Continue executing - Continue, - // Disconnected (i.e. go to main menu) - Disconnect, -} - /// Represents an active game session (i.e., the one being played). impl SessionState { /// Create a new `SessionState`. @@ -87,10 +87,7 @@ impl SessionState { } => { self.hud.new_message(event); }, - client::Event::Disconnect => { - log::warn!("disconnect"); - return Ok(TickAction::Disconnect); - }, + client::Event::Disconnect => return Ok(TickAction::Disconnect), client::Event::DisconnectionNotification(time) => { let message = match time { 0 => String::from("Goodbye!"), From fb4aba9bb7455d14b47ae7728f636b789d0bd91d Mon Sep 17 00:00:00 2001 From: Capucho Date: Sun, 8 Mar 2020 08:54:29 +0000 Subject: [PATCH 3/4] Fix the spam on disconnect --- client/src/lib.rs | 5 +---- common/src/msg/mod.rs | 1 - server/src/sys/message.rs | 9 +-------- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index c44c787e6b..aa2447ce30 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -199,10 +199,7 @@ impl Client { } /// Send disconnect message to the server - pub fn request_logout(&mut self) { - self.postbox.send_message(ClientMsg::Disconnect); - self.client_state = ClientState::Disconnected; - } + pub fn request_logout(&mut self) { self.postbox.send_message(ClientMsg::Disconnect); } /// Request a state transition to `ClientState::Registered` from an ingame /// state. diff --git a/common/src/msg/mod.rs b/common/src/msg/mod.rs index 411763607f..1baee67e15 100644 --- a/common/src/msg/mod.rs +++ b/common/src/msg/mod.rs @@ -16,7 +16,6 @@ pub enum ClientState { Registered, Spectator, Character, - Disconnected, } pub const MAX_BYTES_CHAT_MSG: usize = 256; diff --git a/server/src/sys/message.rs b/server/src/sys/message.rs index b040b20a2d..d86101687e 100644 --- a/server/src/sys/message.rs +++ b/server/src/sys/message.rs @@ -91,7 +91,7 @@ impl<'a> System<'a> for Sys { || client.postbox.error().is_some() // Postbox error { - disconnect = true; + server_emitter.emit(ServerEvent::ClientDisconnect(entity)); } else if time - client.last_ping > CLIENT_TIMEOUT * 0.5 { // Try pinging the client if the timeout is nearing. client.postbox.send_message(ServerMsg::Ping); @@ -111,7 +111,6 @@ impl<'a> System<'a> for Sys { server_emitter.emit(ServerEvent::ExitIngame { entity }); }, ClientState::Pending => {}, - ClientState::Disconnected => unreachable!(), }, // Request spectator state ClientMsg::Spectate => match client.client_state { @@ -122,7 +121,6 @@ impl<'a> System<'a> for Sys { client.allow_state(ClientState::Spectator) }, ClientState::Pending => {}, - ClientState::Disconnected => unreachable!(), }, // Valid player ClientMsg::Register { player, password } if player.is_valid() => { @@ -189,7 +187,6 @@ impl<'a> System<'a> for Sys { }, ClientState::Character => client.error_state(RequestStateError::Already), ClientState::Pending => {}, - ClientState::Disconnected => unreachable!(), }, ClientMsg::ControllerInputs(inputs) => match client.client_state { ClientState::Connected @@ -203,7 +200,6 @@ impl<'a> System<'a> for Sys { } }, ClientState::Pending => {}, - ClientState::Disconnected => unreachable!(), }, ClientMsg::ControlEvent(event) => match client.client_state { ClientState::Connected @@ -217,7 +213,6 @@ impl<'a> System<'a> for Sys { } }, ClientState::Pending => {}, - ClientState::Disconnected => unreachable!(), }, ClientMsg::ChatMsg { message } => match client.client_state { ClientState::Connected => client.error_state(RequestStateError::Impossible), @@ -232,7 +227,6 @@ impl<'a> System<'a> for Sys { ), }, ClientState::Pending => {}, - ClientState::Disconnected => unreachable!(), }, ClientMsg::PlayerPhysics { pos, vel, ori } => match client.client_state { ClientState::Character => { @@ -273,7 +267,6 @@ impl<'a> System<'a> for Sys { } }, ClientState::Pending => {}, - ClientState::Disconnected => unreachable!(), }, // Always possible. ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), From a391f2e0f299aff0d00259a1b8fe637686721d5f Mon Sep 17 00:00:00 2001 From: Capucho Date: Sun, 8 Mar 2020 20:31:27 +0000 Subject: [PATCH 4/4] Switch states instead of popping --- client/src/lib.rs | 8 -------- voxygen/src/menu/char_selection/mod.rs | 7 +------ voxygen/src/session.rs | 8 ++++++++ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index aa2447ce30..e071c566e5 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -77,8 +77,6 @@ pub struct Client { loaded_distance: f32, pending_chunks: HashMap, Instant>, - - disconnected: bool, } impl Client { @@ -165,8 +163,6 @@ impl Client { loaded_distance: 0.0, pending_chunks: HashMap::new(), - - disconnected: false, }) } @@ -703,7 +699,6 @@ impl Client { ); }, ServerMsg::Disconnect => { - self.disconnected = true; frontend_events.push(Event::Disconnect); self.postbox.send_message(ClientMsg::Terminate); }, @@ -718,9 +713,6 @@ impl Client { Ok(frontend_events) } - // Get's whether or not the client just disconnected - pub fn disconnected(&self) -> bool { self.disconnected } - /// Get the player's entity. pub fn entity(&self) -> EcsEntity { self.entity } diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 0931126e37..23b43d7eb9 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -39,11 +39,6 @@ impl PlayState for CharSelectionState { // Set up an fps clock. let mut clock = Clock::start(); - // Check if we just disconnected, if so go to main menu - if self.client.borrow().disconnected() { - return PlayStateResult::Pop; - } - let mut current_client_state = self.client.borrow().get_client_state(); while let ClientState::Pending | ClientState::Registered = current_client_state { // Handle window events @@ -83,7 +78,7 @@ impl PlayState for CharSelectionState { char_data.body, char_data.tool, ); - return PlayStateResult::Push(Box::new(SessionState::new( + return PlayStateResult::Switch(Box::new(SessionState::new( global_state, self.client.clone(), ))); diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 7e36d44543..c6de6e40e0 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -3,6 +3,7 @@ use crate::{ hud::{DebugInfo, Event as HudEvent, Hud}, i18n::{i18n_asset_key, VoxygenLocalization}, key_state::KeyState, + menu::char_selection::CharSelectionState, render::Renderer, scene::{camera, Scene, SceneData}, window::{Event, GameInput}, @@ -680,6 +681,13 @@ impl PlayState for SessionState { current_client_state = self.client.borrow().get_client_state(); } + if let ClientState::Registered = current_client_state { + return PlayStateResult::Switch(Box::new(CharSelectionState::new( + global_state, + self.client.clone(), + ))); + } + PlayStateResult::Pop }