Implement the Player Timeout as config

This commit is contained in:
Marcel Märtens 2020-09-06 21:24:52 +02:00
parent 198c12babc
commit 961b8a4d7c
5 changed files with 22 additions and 16 deletions

View File

@ -52,14 +52,6 @@ use tracing::{debug, error, trace, warn};
use uvth::{ThreadPool, ThreadPoolBuilder}; use uvth::{ThreadPool, ThreadPoolBuilder};
use vek::*; use vek::*;
// The duration of network inactivity until the player is kicked
// @TODO: in the future, this should be configurable on the server
// and be provided to the client
const SERVER_TIMEOUT: f64 = 40.0;
// After this duration has elapsed, the user will begin getting kick warnings in
// their chat window
const SERVER_TIMEOUT_GRACE_PERIOD: f64 = 14.0;
const PING_ROLLING_AVERAGE_SECS: usize = 10; const PING_ROLLING_AVERAGE_SECS: usize = 10;
pub enum Event { pub enum Event {
@ -117,6 +109,7 @@ pub struct Client {
participant: Option<Participant>, participant: Option<Participant>,
singleton_stream: Stream, singleton_stream: Stream,
client_timeout: Duration,
last_server_ping: f64, last_server_ping: f64,
last_server_pong: f64, last_server_pong: f64,
last_ping_delta: f64, last_ping_delta: f64,
@ -173,6 +166,7 @@ impl Client {
world_map, world_map,
recipe_book, recipe_book,
max_group_size, max_group_size,
client_timeout,
) = block_on(async { ) = block_on(async {
loop { loop {
match stream.recv().await? { match stream.recv().await? {
@ -181,6 +175,7 @@ impl Client {
server_info, server_info,
time_of_day, time_of_day,
max_group_size, max_group_size,
client_timeout,
world_map, world_map,
recipe_book, recipe_book,
} => { } => {
@ -358,6 +353,7 @@ impl Client {
(world_map, map_size, map_bounds), (world_map, map_size, map_bounds),
recipe_book, recipe_book,
max_group_size, max_group_size,
client_timeout,
)); ));
}, },
ServerMsg::TooManyPlayers => break Err(Error::TooManyPlayers), ServerMsg::TooManyPlayers => break Err(Error::TooManyPlayers),
@ -399,6 +395,7 @@ impl Client {
_network: network, _network: network,
participant: Some(participant), participant: Some(participant),
singleton_stream: stream, singleton_stream: stream,
client_timeout,
last_server_ping: 0.0, last_server_ping: 0.0,
last_server_pong: 0.0, last_server_pong: 0.0,
@ -1434,7 +1431,10 @@ impl Client {
let duration_since_last_pong = self.state.get_time() - self.last_server_pong; let duration_since_last_pong = self.state.get_time() - self.last_server_pong;
// Dispatch a notification to the HUD warning they will be kicked in {n} seconds // Dispatch a notification to the HUD warning they will be kicked in {n} seconds
if duration_since_last_pong >= SERVER_TIMEOUT_GRACE_PERIOD const KICK_WARNING_AFTER_REL_TO_TIMEOUT_FRACTION: f64 = 0.75;
if duration_since_last_pong
>= (self.client_timeout.as_secs() as f64
* KICK_WARNING_AFTER_REL_TO_TIMEOUT_FRACTION)
&& self.state.get_time() - duration_since_last_pong > 0. && self.state.get_time() - duration_since_last_pong > 0.
{ {
frontend_events.push(Event::DisconnectionNotification( frontend_events.push(Event::DisconnectionNotification(
@ -1453,7 +1453,9 @@ impl Client {
) )
})?; })?;
if handles_msg == 0 && self.state.get_time() - self.last_server_pong > SERVER_TIMEOUT { if handles_msg == 0
&& self.state.get_time() - self.last_server_pong > self.client_timeout.as_secs() as f64
{
return Err(Error::ServerTimeout); return Err(Error::ServerTimeout);
} }

View File

@ -11,6 +11,7 @@ use crate::{
use authc::AuthClientError; use authc::AuthClientError;
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration;
use vek::*; use vek::*;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -189,6 +190,7 @@ pub enum ServerMsg {
server_info: ServerInfo, server_info: ServerInfo,
time_of_day: state::TimeOfDay, time_of_day: state::TimeOfDay,
max_group_size: u32, max_group_size: u32,
client_timeout: Duration,
world_map: WorldMapMsg, world_map: WorldMapMsg,
recipe_book: RecipeBook, recipe_book: RecipeBook,
}, },

View File

@ -70,8 +70,6 @@ use world::{
#[macro_use] extern crate diesel; #[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_migrations; #[macro_use] extern crate diesel_migrations;
const CLIENT_TIMEOUT: f64 = 40.0; // Seconds
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct SpawnPoint(Vec3<f32>); struct SpawnPoint(Vec3<f32>);
@ -753,6 +751,7 @@ impl Server {
server_info: self.get_server_info(), server_info: self.get_server_info(),
time_of_day: *self.state.ecs().read_resource(), time_of_day: *self.state.ecs().read_resource(),
max_group_size: self.settings().max_player_group_size, max_group_size: self.settings().max_player_group_size,
client_timeout: self.settings().client_timeout,
world_map: self.map.clone(), world_map: self.map.clone(),
recipe_book: (&*default_recipe_book()).clone(), recipe_book: (&*default_recipe_book()).clone(),
}); });

View File

@ -1,6 +1,6 @@
use portpicker::pick_unused_port; use portpicker::pick_unused_port;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fs, io::prelude::*, net::SocketAddr, path::PathBuf}; use std::{fs, io::prelude::*, net::SocketAddr, path::PathBuf, time::Duration};
use tracing::{error, warn}; use tracing::{error, warn};
use world::sim::FileOpts; use world::sim::FileOpts;
@ -27,6 +27,7 @@ pub struct ServerSettings {
pub max_view_distance: Option<u32>, pub max_view_distance: Option<u32>,
pub banned_words_files: Vec<PathBuf>, pub banned_words_files: Vec<PathBuf>,
pub max_player_group_size: u32, pub max_player_group_size: u32,
pub client_timeout: Duration,
} }
impl Default for ServerSettings { impl Default for ServerSettings {
@ -47,6 +48,7 @@ impl Default for ServerSettings {
max_view_distance: Some(30), max_view_distance: Some(30),
banned_words_files: Vec::new(), banned_words_files: Vec::new(),
max_player_group_size: 6, max_player_group_size: 6,
client_timeout: Duration::from_secs(40),
} }
} }
} }
@ -113,6 +115,7 @@ impl ServerSettings {
* to use admin commands or not */ * to use admin commands or not */
persistence_db_dir, persistence_db_dir,
max_view_distance: None, max_view_distance: None,
client_timeout: Duration::from_secs(180),
..load // Fill in remaining fields from server_settings.ron. ..load // Fill in remaining fields from server_settings.ron.
} }
} }

View File

@ -1,7 +1,7 @@
use super::SysTimer; use super::SysTimer;
use crate::{ use crate::{
alias_validator::AliasValidator, client::Client, login_provider::LoginProvider, alias_validator::AliasValidator, client::Client, login_provider::LoginProvider,
persistence::character::CharacterLoader, ServerSettings, CLIENT_TIMEOUT, persistence::character::CharacterLoader, ServerSettings,
}; };
use common::{ use common::{
comp::{ comp::{
@ -519,7 +519,7 @@ impl<'a> System<'a> for Sys {
// Update client ping. // Update client ping.
if cnt > 0 { if cnt > 0 {
client.last_ping = time.0 client.last_ping = time.0
} else if time.0 - client.last_ping > CLIENT_TIMEOUT } else if time.0 - client.last_ping > settings.client_timeout.as_secs() as f64
// Timeout // Timeout
{ {
info!(?entity, "timeout error with client, disconnecting"); info!(?entity, "timeout error with client, disconnecting");
@ -529,7 +529,7 @@ impl<'a> System<'a> for Sys {
{ {
debug!(?entity, "postbox error with client, disconnecting"); debug!(?entity, "postbox error with client, disconnecting");
server_emitter.emit(ServerEvent::ClientDisconnect(entity)); server_emitter.emit(ServerEvent::ClientDisconnect(entity));
} else if time.0 - client.last_ping > CLIENT_TIMEOUT * 0.5 { } else if time.0 - client.last_ping > settings.client_timeout.as_secs() as f64 * 0.5 {
// Try pinging the client if the timeout is nearing. // Try pinging the client if the timeout is nearing.
client.notify(ServerMsg::Ping); client.notify(ServerMsg::Ping);
} }