diff --git a/client/src/lib.rs b/client/src/lib.rs index 09841e3fa7..27f4d9f2ea 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -222,7 +222,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 @@ -722,6 +722,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 1c04fece94..ad9e8411f0 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 b524c22fbc..fab604c10c 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!(), }, // Request registered state (login) ClientMsg::Register { @@ -200,6 +202,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 @@ -213,6 +216,7 @@ impl<'a> System<'a> for Sys { } }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, ClientMsg::ControlEvent(event) => match client.client_state { ClientState::Connected @@ -226,6 +230,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), @@ -240,6 +245,7 @@ impl<'a> System<'a> for Sys { ), }, ClientState::Pending => {}, + ClientState::Disconnected => unreachable!(), }, ClientMsg::PlayerPhysics { pos, vel, ori } => match client.client_state { ClientState::Character => { @@ -280,6 +286,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; + }, } }