mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Groundwork for fixing #36 and rewrite of client timeouts so that they don't use Instant and Duration
This commit is contained in:
parent
68fbc2d1b6
commit
a97b694dfe
@ -40,11 +40,11 @@ use vek::*;
|
|||||||
// The duration of network inactivity until the player is kicked
|
// The duration of network inactivity until the player is kicked
|
||||||
// @TODO: in the future, this should be configurable on the server
|
// @TODO: in the future, this should be configurable on the server
|
||||||
// and be provided to the client
|
// and be provided to the client
|
||||||
const SERVER_TIMEOUT: Duration = Duration::from_secs(20);
|
const SERVER_TIMEOUT: f64 = 20.0;
|
||||||
|
|
||||||
// After this duration has elapsed, the user will begin getting kick warnings in
|
// After this duration has elapsed, the user will begin getting kick warnings in
|
||||||
// their chat window
|
// their chat window
|
||||||
const SERVER_TIMEOUT_GRACE_PERIOD: Duration = Duration::from_secs(14);
|
const SERVER_TIMEOUT_GRACE_PERIOD: f64 = 14.0;
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Chat {
|
Chat {
|
||||||
@ -64,8 +64,8 @@ pub struct Client {
|
|||||||
|
|
||||||
postbox: PostBox<ClientMsg, ServerMsg>,
|
postbox: PostBox<ClientMsg, ServerMsg>,
|
||||||
|
|
||||||
last_server_ping: Instant,
|
last_server_ping: f64,
|
||||||
last_server_pong: Instant,
|
last_server_pong: f64,
|
||||||
last_ping_delta: f64,
|
last_ping_delta: f64,
|
||||||
|
|
||||||
tick: u64,
|
tick: u64,
|
||||||
@ -152,8 +152,8 @@ impl Client {
|
|||||||
|
|
||||||
postbox,
|
postbox,
|
||||||
|
|
||||||
last_server_ping: Instant::now(),
|
last_server_ping: 0.0,
|
||||||
last_server_pong: Instant::now(),
|
last_server_pong: 0.0,
|
||||||
last_ping_delta: 0.0,
|
last_ping_delta: 0.0,
|
||||||
|
|
||||||
tick: 0,
|
tick: 0,
|
||||||
@ -481,9 +481,9 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send a ping to the server once every second
|
// Send a ping to the server once every second
|
||||||
if Instant::now().duration_since(self.last_server_ping) > Duration::from_secs(1) {
|
if self.state.get_time() - self.last_server_ping > 1. {
|
||||||
self.postbox.send_message(ClientMsg::Ping);
|
self.postbox.send_message(ClientMsg::Ping);
|
||||||
self.last_server_ping = Instant::now();
|
self.last_server_ping = self.state.get_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) Update the server about the player's physics attributes.
|
// 6) Update the server about the player's physics attributes.
|
||||||
@ -528,16 +528,14 @@ impl Client {
|
|||||||
// Check that we have an valid connection.
|
// Check that we have an valid connection.
|
||||||
// Use the last ping time as a 1s rate limiter, we only notify the user once per
|
// Use the last ping time as a 1s rate limiter, we only notify the user once per
|
||||||
// second
|
// second
|
||||||
if Instant::now().duration_since(self.last_server_ping) > Duration::from_secs(1) {
|
if self.state.get_time() - self.last_server_ping > 1. {
|
||||||
let duration_since_last_pong = Instant::now().duration_since(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.as_secs() >= SERVER_TIMEOUT_GRACE_PERIOD.as_secs() {
|
if duration_since_last_pong >= SERVER_TIMEOUT_GRACE_PERIOD {
|
||||||
if let Some(seconds_until_kick) =
|
if self.state.get_time() - duration_since_last_pong > 0. {
|
||||||
SERVER_TIMEOUT.checked_sub(duration_since_last_pong)
|
|
||||||
{
|
|
||||||
frontend_events.push(Event::DisconnectionNotification(
|
frontend_events.push(Event::DisconnectionNotification(
|
||||||
seconds_until_kick.as_secs(),
|
(self.state.get_time() - duration_since_last_pong).round() as u64,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -591,11 +589,10 @@ impl Client {
|
|||||||
|
|
||||||
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
||||||
ServerMsg::Pong => {
|
ServerMsg::Pong => {
|
||||||
self.last_server_pong = Instant::now();
|
self.last_server_pong = self.state.get_time();
|
||||||
|
|
||||||
self.last_ping_delta = Instant::now()
|
self.last_ping_delta =
|
||||||
.duration_since(self.last_server_ping)
|
(self.state.get_time() - self.last_server_ping).round();
|
||||||
.as_secs_f64();
|
|
||||||
},
|
},
|
||||||
ServerMsg::ChatMsg { message, chat_type } => {
|
ServerMsg::ChatMsg { message, chat_type } => {
|
||||||
frontend_events.push(Event::Chat { message, chat_type })
|
frontend_events.push(Event::Chat { message, chat_type })
|
||||||
@ -712,7 +709,7 @@ impl Client {
|
|||||||
} else if let Some(err) = self.postbox.error() {
|
} else if let Some(err) = self.postbox.error() {
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
// We regularily ping in the tick method
|
// We regularily ping in the tick method
|
||||||
} else if Instant::now().duration_since(self.last_server_pong) > SERVER_TIMEOUT {
|
} else if self.state.get_time() - self.last_server_pong > SERVER_TIMEOUT {
|
||||||
return Err(Error::ServerTimeout);
|
return Err(Error::ServerTimeout);
|
||||||
}
|
}
|
||||||
Ok(frontend_events)
|
Ok(frontend_events)
|
||||||
|
@ -357,7 +357,7 @@ impl Show {
|
|||||||
|
|
||||||
fn toggle_ui(&mut self) { self.ui = !self.ui; }
|
fn toggle_ui(&mut self) { self.ui = !self.ui; }
|
||||||
|
|
||||||
fn toggle_windows(&mut self) {
|
fn toggle_windows(&mut self, global_state: &mut GlobalState) {
|
||||||
if self.bag
|
if self.bag
|
||||||
|| self.esc_menu
|
|| self.esc_menu
|
||||||
|| self.map
|
|| self.map
|
||||||
@ -379,9 +379,21 @@ impl Show {
|
|||||||
self.character_window = false;
|
self.character_window = false;
|
||||||
self.open_windows = Windows::None;
|
self.open_windows = Windows::None;
|
||||||
self.want_grab = true;
|
self.want_grab = true;
|
||||||
|
|
||||||
|
// Unpause the game if we are on singleplayer
|
||||||
|
if let Some(ref singleplayer) = global_state.singleplayer {
|
||||||
|
singleplayer.pause(false);
|
||||||
|
global_state.paused = false;
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
self.esc_menu = true;
|
self.esc_menu = true;
|
||||||
self.want_grab = false;
|
self.want_grab = false;
|
||||||
|
|
||||||
|
// Pause the game if we are on singleplayer
|
||||||
|
if let Some(ref singleplayer) = global_state.singleplayer {
|
||||||
|
singleplayer.pause(true);
|
||||||
|
global_state.paused = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1992,7 +2004,7 @@ impl Hud {
|
|||||||
self.ui.focus_widget(None);
|
self.ui.focus_widget(None);
|
||||||
} else {
|
} else {
|
||||||
// Close windows on esc
|
// Close windows on esc
|
||||||
self.show.toggle_windows();
|
self.show.toggle_windows(global_state);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
|
@ -32,6 +32,7 @@ use crate::{
|
|||||||
menu::main::MainMenuState,
|
menu::main::MainMenuState,
|
||||||
meta::Meta,
|
meta::Meta,
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
|
singleplayer::Singleplayer,
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
use common::assets::{load, load_expect};
|
use common::assets::{load, load_expect};
|
||||||
@ -45,6 +46,8 @@ pub struct GlobalState {
|
|||||||
window: Window,
|
window: Window,
|
||||||
audio: AudioFrontend,
|
audio: AudioFrontend,
|
||||||
info_message: Option<String>,
|
info_message: Option<String>,
|
||||||
|
singleplayer: Option<Singleplayer>,
|
||||||
|
paused: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalState {
|
impl GlobalState {
|
||||||
@ -135,6 +138,8 @@ fn main() {
|
|||||||
settings,
|
settings,
|
||||||
meta,
|
meta,
|
||||||
info_message: None,
|
info_message: None,
|
||||||
|
singleplayer: None,
|
||||||
|
paused: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to load the localization and log missing entries
|
// Try to load the localization and log missing entries
|
||||||
|
@ -18,7 +18,6 @@ use ui::{Event as MainMenuEvent, MainMenuUi};
|
|||||||
|
|
||||||
pub struct MainMenuState {
|
pub struct MainMenuState {
|
||||||
main_menu_ui: MainMenuUi,
|
main_menu_ui: MainMenuUi,
|
||||||
singleplayer: Option<Singleplayer>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainMenuState {
|
impl MainMenuState {
|
||||||
@ -26,7 +25,6 @@ impl MainMenuState {
|
|||||||
pub fn new(global_state: &mut GlobalState) -> Self {
|
pub fn new(global_state: &mut GlobalState) -> Self {
|
||||||
Self {
|
Self {
|
||||||
main_menu_ui: MainMenuUi::new(global_state),
|
main_menu_ui: MainMenuUi::new(global_state),
|
||||||
singleplayer: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,7 +45,7 @@ impl PlayState for MainMenuState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset singleplayer server if it was running already
|
// Reset singleplayer server if it was running already
|
||||||
self.singleplayer = None;
|
global_state.singleplayer = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Handle window events.
|
// Handle window events.
|
||||||
@ -119,7 +117,7 @@ impl PlayState for MainMenuState {
|
|||||||
// client_init contains Some(ClientInit), which spawns a thread which
|
// client_init contains Some(ClientInit), which spawns a thread which
|
||||||
// contains a TcpStream::connect() call This call is
|
// contains a TcpStream::connect() call This call is
|
||||||
// blocking TODO fix when the network rework happens
|
// blocking TODO fix when the network rework happens
|
||||||
self.singleplayer = None;
|
global_state.singleplayer = None;
|
||||||
client_init = None;
|
client_init = None;
|
||||||
self.main_menu_ui.cancel_connection();
|
self.main_menu_ui.cancel_connection();
|
||||||
},
|
},
|
||||||
@ -127,7 +125,7 @@ impl PlayState for MainMenuState {
|
|||||||
MainMenuEvent::StartSingleplayer => {
|
MainMenuEvent::StartSingleplayer => {
|
||||||
let (singleplayer, server_settings) = Singleplayer::new(None); // TODO: Make client and server use the same thread pool
|
let (singleplayer, server_settings) = Singleplayer::new(None); // TODO: Make client and server use the same thread pool
|
||||||
|
|
||||||
self.singleplayer = Some(singleplayer);
|
global_state.singleplayer = Some(singleplayer);
|
||||||
|
|
||||||
attempt_login(
|
attempt_login(
|
||||||
global_state,
|
global_state,
|
||||||
|
@ -379,13 +379,15 @@ impl PlayState for SessionState {
|
|||||||
|
|
||||||
self.inputs.look_dir = cam_dir;
|
self.inputs.look_dir = cam_dir;
|
||||||
|
|
||||||
// Perform an in-game tick.
|
if !global_state.paused {
|
||||||
if let Err(err) = self.tick(clock.get_avg_delta()) {
|
// Perform an in-game tick.
|
||||||
global_state.info_message =
|
if let Err(err) = self.tick(clock.get_avg_delta()) {
|
||||||
Some(localized_strings.get("common.connection_lost").to_owned());
|
global_state.info_message =
|
||||||
error!("[session] Failed to tick the scene: {:?}", err);
|
Some(localized_strings.get("common.connection_lost").to_owned());
|
||||||
|
error!("[session] Failed to tick the scene: {:?}", err);
|
||||||
|
|
||||||
return PlayStateResult::Pop;
|
return PlayStateResult::Pop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maintain global state.
|
// Maintain global state.
|
||||||
@ -609,13 +611,15 @@ impl PlayState for SessionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maintain the scene.
|
if !global_state.paused {
|
||||||
self.scene.maintain(
|
// Maintain the scene.
|
||||||
global_state.window.renderer_mut(),
|
self.scene.maintain(
|
||||||
&mut global_state.audio,
|
global_state.window.renderer_mut(),
|
||||||
&self.client.borrow(),
|
&mut global_state.audio,
|
||||||
global_state.settings.graphics.gamma,
|
&self.client.borrow(),
|
||||||
);
|
global_state.settings.graphics.gamma,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Render the session.
|
// Render the session.
|
||||||
self.render(global_state.window.renderer_mut());
|
self.render(global_state.window.renderer_mut());
|
||||||
|
@ -12,6 +12,7 @@ const TPS: u64 = 30;
|
|||||||
|
|
||||||
enum Msg {
|
enum Msg {
|
||||||
Stop,
|
Stop,
|
||||||
|
Pause(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to start and stop the background thread running the server
|
/// Used to start and stop the background thread running the server
|
||||||
@ -50,6 +51,8 @@ impl Singleplayer {
|
|||||||
settings,
|
settings,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pause(&self, paused: bool) { let _ = self.sender.send(Msg::Pause(paused)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Singleplayer {
|
impl Drop for Singleplayer {
|
||||||
@ -64,8 +67,26 @@ fn run_server(mut server: Server, rec: Receiver<Msg>) {
|
|||||||
|
|
||||||
// Set up an fps clock
|
// Set up an fps clock
|
||||||
let mut clock = Clock::start();
|
let mut clock = Clock::start();
|
||||||
|
let mut paused = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
match rec.try_recv() {
|
||||||
|
Ok(msg) => match msg {
|
||||||
|
Msg::Stop => break,
|
||||||
|
Msg::Pause(val) => paused = val,
|
||||||
|
},
|
||||||
|
Err(err) => match err {
|
||||||
|
TryRecvError::Empty => (),
|
||||||
|
TryRecvError::Disconnected => break,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if paused {
|
||||||
|
// Wait for the next tick.
|
||||||
|
clock.tick(Duration::from_millis(1000 / TPS));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let events = server
|
let events = server
|
||||||
.tick(Input::default(), clock.get_last_delta())
|
.tick(Input::default(), clock.get_last_delta())
|
||||||
.expect("Failed to tick server!");
|
.expect("Failed to tick server!");
|
||||||
@ -81,14 +102,6 @@ fn run_server(mut server: Server, rec: Receiver<Msg>) {
|
|||||||
// Clean up the server after a tick.
|
// Clean up the server after a tick.
|
||||||
server.cleanup();
|
server.cleanup();
|
||||||
|
|
||||||
match rec.try_recv() {
|
|
||||||
Ok(_msg) => break,
|
|
||||||
Err(err) => match err {
|
|
||||||
TryRecvError::Empty => (),
|
|
||||||
TryRecvError::Disconnected => break,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the next tick.
|
// Wait for the next tick.
|
||||||
clock.tick(Duration::from_millis(1000 / TPS));
|
clock.tick(Duration::from_millis(1000 / TPS));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user