diff --git a/client/src/lib.rs b/client/src/lib.rs index f61d59e9c2..40f9b6e058 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -241,15 +241,12 @@ impl Client { self.pending_chunks.remove(&key); }, ServerMsg::StateAnswer(Ok(state)) => { - println!("ok state: {:?}", state); self.client_state = state; }, ServerMsg::StateAnswer(Err((error, state))) => { - println!("err state: {:?}", state); self.client_state = state; }, - ServerMsg::ForceState { state } => { - println!("forced state: {:?}", state); + ServerMsg::ForceState(state) => { self.client_state = state; }, } diff --git a/common/src/msg/mod.rs b/common/src/msg/mod.rs index 9c3fafa00b..d0acbcac9e 100644 --- a/common/src/msg/mod.rs +++ b/common/src/msg/mod.rs @@ -7,9 +7,10 @@ pub use self::server::{ServerMsg, RequestStateError}; pub use self::client::ClientMsg; pub use self::ecs_packet::EcsPacket; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub enum ClientState { Disconnected, + Connected, Spectator, Character, } diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 5ad7a023b2..86fc96c665 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -15,9 +15,7 @@ pub enum RequestStateError { #[derive(Clone, Serialize, Deserialize)] pub enum ServerMsg { StateAnswer(Result), - ForceState { - state: ClientState, - }, + ForceState(ClientState), InitialSync { ecs_state: sphynx::StatePackage, player_entity_uid: u64, diff --git a/server/src/client.rs b/server/src/client.rs index 8dcb1edfce..8d36c6e2c0 100644 --- a/server/src/client.rs +++ b/server/src/client.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use specs::Entity as EcsEntity; use common::{ comp, - msg::{ServerMsg, ClientMsg, ClientState}, + msg::{ServerMsg, ClientMsg, ClientState, RequestStateError}, net::PostBox, }; use crate::Error; @@ -17,6 +17,20 @@ impl Client { pub fn notify(&mut self, msg: ServerMsg) { self.postbox.send_message(msg); } + pub fn allow_state(&mut self, new_state: ClientState) { + self.client_state = new_state; + self.postbox.send_message(ServerMsg::StateAnswer( + Ok(new_state))); + } + pub fn error_state(&mut self, error: RequestStateError) { + self.postbox.send_message(ServerMsg::StateAnswer( + Err((error, self.client_state)))); + } + pub fn force_state(&mut self, new_state: ClientState) { + self.client_state = new_state; + self.postbox.send_message(ServerMsg::ForceState( + new_state)); + } } pub struct Clients { diff --git a/server/src/lib.rs b/server/src/lib.rs index c2504c4912..9f3a578c74 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -250,51 +250,44 @@ impl Server { for msg in new_msgs { match msg { ClientMsg::RequestState(requested_state) => match requested_state { - ClientState::Spectator => match client.client_state { - // Use ClientMsg::Connect instead - ClientState::Disconnected => {}, - ClientState::Spectator => { - // Already - client.postbox.send_message(ServerMsg::StateAnswer( - Err((RequestStateError::Already, ClientState::Spectator)))); - }, - ClientState::Character => { - // Always allow - client.postbox.send_message(ServerMsg::StateAnswer( - Ok(ClientState::Spectator))); - }, - }, - // Use ClientMsg::Character instead - ClientState::Character => { unimplemented!("TODO: Check for previously used character"); }, ClientState::Disconnected => disconnect = true, + ClientState::Connected => match client.client_state { + ClientState::Disconnected => {}, // Use ClientMsg::Connect instead + ClientState::Connected => client.error_state(RequestStateError::Already), + ClientState::Spectator => client.allow_state(ClientState::Connected), + ClientState::Character => client.allow_state(ClientState::Connected), + }, + ClientState::Spectator => match requested_state { + ClientState::Disconnected => {}, // Become Connected first + ClientState::Connected => client.allow_state(ClientState::Spectator), + ClientState::Spectator => client.error_state(RequestStateError::Already), + ClientState::Character => client.allow_state(ClientState::Spectator), + }, + ClientState::Character => {}, // Use ClientMsg::Character instead }, ClientMsg::Connect { player } => match client.client_state { ClientState::Disconnected => Self::initialize_client(state, entity, client, player), _ => {}, }, ClientMsg::Character(character) => match client.client_state { - ClientState::Spectator => Self::create_player_character(state, entity, client, character), - // Currently only possible from spectator - _ => disconnect = true, + ClientState::Disconnected => {}, + ClientState::Connected | ClientState::Spectator => + Self::create_player_character(state, entity, client, character), + ClientState::Character => client.error_state(RequestStateError::Already), }, - - // Always possible - ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), - ClientMsg::Pong => {} - ClientMsg::Disconnect => disconnect = true, - ClientMsg::Chat(msg) => match client.client_state { - ClientState::Disconnected => {} - _ => new_chat_msgs.push((entity, msg)), + ClientState::Disconnected => {}, + ClientState::Connected => new_chat_msgs.push((entity, msg)), + ClientState::Spectator => new_chat_msgs.push((entity, msg)), + ClientState::Character => new_chat_msgs.push((entity, msg)), }, - ClientMsg::PlayerAnimation(animation_history) => match client.client_state { - ClientState::Character => { - state.write_component(entity, animation_history); - } + // Only characters can send animations + ClientState::Character => state.write_component(entity, animation_history), _ => disconnect = true, }, ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state { + // Only characters send their position ClientState::Character => { state.write_component(entity, pos); state.write_component(entity, vel); @@ -303,6 +296,8 @@ impl Server { _ => disconnect = true, }, ClientMsg::TerrainChunkRequest { key } => match client.client_state { + ClientState::Disconnected => {}, + ClientState::Connected => disconnect = true, ClientState::Spectator | ClientState::Character => { match state.terrain().get_key(key) { Some(chunk) => {} /*client.postbox.send_message(ServerMsg::TerrainChunkUpdate { @@ -312,8 +307,11 @@ impl Server { None => requested_chunks.push(key), } }, - ClientState::Disconnected => {}, } + // Always possible + ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), + ClientMsg::Pong => {}, + ClientMsg::Disconnect => disconnect = true, } } } else if state.get_time() - client.last_ping > CLIENT_TIMEOUT || // Timeout @@ -327,7 +325,6 @@ impl Server { } if disconnect { - println!("Someone disconnected!"); disconnected_clients.push(entity); client.postbox.send_message(ServerMsg::StateAnswer( Err((RequestStateError::Impossible, ClientState::Disconnected)))); @@ -410,8 +407,7 @@ impl Server { } // Tell the client his request was successful - client.notify(ServerMsg::StateAnswer(Ok(ClientState::Spectator))); - client.client_state = ClientState::Spectator; + client.allow_state(ClientState::Connected); } /// Sync client states with the most up to date information