Merge branch 'capucho/voxygen-logout-timeout' into 'master'

FIX #513 logout timeout

See merge request veloren/veloren!837
This commit is contained in:
Acrimon 2020-03-10 22:12:29 +00:00
commit 406767ae31
6 changed files with 47 additions and 36 deletions

View File

@ -220,10 +220,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;
}
pub fn request_logout(&mut self) { self.postbox.send_message(ClientMsg::Disconnect); }
/// Request a state transition to `ClientState::Registered` from an ingame
/// state.
@ -722,6 +719,7 @@ impl Client {
},
ServerMsg::Disconnect => {
frontend_events.push(Event::Disconnect);
self.postbox.send_message(ClientMsg::Terminate);
},
}
}

View File

@ -35,4 +35,5 @@ pub enum ClientMsg {
key: Vec2<i32>,
},
Disconnect,
Terminate,
}

View File

@ -7,7 +7,7 @@ use common::{
sync::{Uid, UidAllocator},
};
use log::error;
use specs::{saveload::MarkerAllocator, Builder, Entity as EcsEntity, WorldExt};
use specs::{saveload::MarkerAllocator, Builder, Entity as EcsEntity, Join, WorldExt};
pub fn handle_exit_ingame(server: &mut Server, entity: EcsEntity) {
let state = server.state_mut();
@ -53,12 +53,19 @@ pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event
}
// Make sure to remove the player from the logged in list. (See AuthProvider)
// And send a disconnected message
{
let players = state.ecs().read_storage::<Player>();
let mut accounts = state.ecs().write_resource::<AuthProvider>();
let mut clients = state.ecs().write_storage::<Client>();
if let Some(player) = players.get(entity) {
accounts.logout(player.uuid());
let msg = ServerMsg::broadcast(format!("{} went offline.", &player.alias));
for client in (&mut clients).join().filter(|c| c.is_registered()) {
client.notify(msg.clone());
}
}
}
// Delete client entity

View File

@ -1,7 +1,7 @@
use super::SysTimer;
use crate::{auth_provider::AuthProvider, client::Client, CLIENT_TIMEOUT};
use common::{
comp::{Admin, Body, CanBuild, Controller, ForceUpdate, Ori, Player, Pos, Stats, Vel},
comp::{Admin, CanBuild, Controller, ForceUpdate, Ori, Player, Pos, Stats, Vel},
event::{EventBus, ServerEvent},
msg::{
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate,
@ -27,7 +27,6 @@ impl<'a> System<'a> for Sys {
ReadExpect<'a, TerrainGrid>,
Write<'a, SysTimer<Self>>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Body>,
ReadStorage<'a, CanBuild>,
ReadStorage<'a, Admin>,
ReadStorage<'a, ForceUpdate>,
@ -51,7 +50,6 @@ impl<'a> System<'a> for Sys {
terrain,
mut timer,
uids,
bodies,
can_build,
admins,
force_updates,
@ -81,7 +79,6 @@ impl<'a> System<'a> for Sys {
let mut new_players = Vec::new();
for (entity, client) in (&entities, &mut clients).join() {
let mut disconnect = false;
let new_msgs = client.postbox.new_messages();
// Update client ping.
@ -91,7 +88,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);
@ -285,25 +282,13 @@ impl<'a> System<'a> for Sys {
ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
ClientMsg::Pong => {},
ClientMsg::Disconnect => {
disconnect = true;
client.postbox.send_message(ServerMsg::Disconnect);
},
ClientMsg::Terminate => {
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
},
}
}
if disconnect {
if let (Some(player), Some(_)) = (
players.get(entity),
// It only shows a message if you had a body (not in char selection)
bodies.get(entity),
) {
new_chat_msgs.push((
None,
ServerMsg::broadcast(format!("{} went offline.", &player.alias)),
));
}
server_emitter.emit(ServerEvent::ClientDisconnect(entity));
client.postbox.send_message(ServerMsg::Disconnect);
}
}
// Handle new players.

View File

@ -78,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(),
)));
@ -141,7 +141,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;
}

View File

@ -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::{AnalogGameInput, Event, GameInput},
@ -24,6 +25,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<RefCell<Client>>,
@ -65,7 +74,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<TickAction, Error> {
self.inputs.tick(dt);
for event in self.client.borrow_mut().tick(
self.inputs.clone(),
@ -79,7 +88,7 @@ impl SessionState {
} => {
self.hud.new_message(event);
},
client::Event::Disconnect => {}, // TODO
client::Event::Disconnect => return Ok(TickAction::Disconnect),
client::Event::DisconnectionNotification(time) => {
let message = match time {
0 => String::from("Goodbye!"),
@ -94,7 +103,7 @@ impl SessionState {
}
}
Ok(())
Ok(TickAction::Continue)
}
/// Clean up the session (and the client attached to it) after a tick.
@ -426,12 +435,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;
},
}
}
@ -704,6 +717,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
}