Better formatting

Former-commit-id: 4316514f4f58dca8ed21dae00fad7a6df36b9ff1
This commit is contained in:
timokoesters
2019-04-23 11:53:45 +02:00
parent 7fc2b3490c
commit df7a145bbc
4 changed files with 138 additions and 103 deletions

View File

@ -4,28 +4,21 @@ pub mod error;
pub mod input; pub mod input;
// Reexports // Reexports
pub use specs::Entity as EcsEntity; pub use crate::{error::Error, input::Input};
pub use specs::join::Join; pub use specs::join::Join;
pub use crate::{ pub use specs::Entity as EcsEntity;
error::Error,
input::Input,
};
use std::{
time::Duration,
net::SocketAddr,
collections::HashSet,
};
use vek::*;
use threadpool::ThreadPool;
use specs::Builder;
use common::{ use common::{
comp, comp,
msg::{ClientMsg, ClientState, ServerMsg},
net::PostBox,
state::State, state::State,
terrain::TerrainChunk, terrain::TerrainChunk,
net::PostBox,
msg::{ClientState, ClientMsg, ServerMsg},
}; };
use specs::Builder;
use std::{collections::HashSet, net::SocketAddr, time::Duration};
use threadpool::ThreadPool;
use vek::*;
const SERVER_TIMEOUT: f64 = 20.0; // Seconds const SERVER_TIMEOUT: f64 = 20.0; // Seconds
@ -51,20 +44,23 @@ pub struct Client {
impl Client { impl Client {
/// Create a new `Client`. /// Create a new `Client`.
#[allow(dead_code)] #[allow(dead_code)]
pub fn new<A: Into<SocketAddr>>( pub fn new<A: Into<SocketAddr>>(addr: A, view_distance: u64) -> Result<Self, Error> {
addr: A,
view_distance: u64,
) -> Result<Self, Error> {
let mut client_state = ClientState::Connected; let mut client_state = ClientState::Connected;
let mut postbox = PostBox::to(addr)?; let mut postbox = PostBox::to(addr)?;
// Wait for initial sync // Wait for initial sync
let (state, entity) = match postbox.next_message() { let (state, entity) = match postbox.next_message() {
Some(ServerMsg::InitialSync { ecs_state, entity_uid }) => { Some(ServerMsg::InitialSync {
ecs_state,
entity_uid,
}) => {
let mut state = State::from_state_package(ecs_state); let mut state = State::from_state_package(ecs_state);
let entity = state.ecs().entity_from_uid(entity_uid).ok_or(Error::ServerWentMad)?; let entity = state
.ecs()
.entity_from_uid(entity_uid)
.ok_or(Error::ServerWentMad)?;
(state, entity) (state, entity)
}, }
_ => return Err(Error::ServerWentMad), _ => return Err(Error::ServerWentMad),
}; };
@ -94,15 +90,21 @@ impl Client {
/// computationally expensive operations that run outside of the main thread (i.e: threads that /// computationally expensive operations that run outside of the main thread (i.e: threads that
/// block on I/O operations are exempt). /// block on I/O operations are exempt).
#[allow(dead_code)] #[allow(dead_code)]
pub fn thread_pool(&self) -> &threadpool::ThreadPool { &self.thread_pool } pub fn thread_pool(&self) -> &threadpool::ThreadPool {
&self.thread_pool
}
/// Get a reference to the client's game state. /// Get a reference to the client's game state.
#[allow(dead_code)] #[allow(dead_code)]
pub fn state(&self) -> &State { &self.state } pub fn state(&self) -> &State {
&self.state
}
/// Get a mutable reference to the client's game state. /// Get a mutable reference to the client's game state.
#[allow(dead_code)] #[allow(dead_code)]
pub fn state_mut(&mut self) -> &mut State { &mut self.state } pub fn state_mut(&mut self) -> &mut State {
&mut self.state
}
/// Get the player's entity /// Get the player's entity
#[allow(dead_code)] #[allow(dead_code)]
@ -147,9 +149,12 @@ impl Client {
println!("Chunk at {:?}", k); println!("Chunk at {:?}", k);
}); });
self.state.write_component(self.entity, comp::Control { self.state.write_component(
move_dir: input.move_dir, self.entity,
}); comp::Control {
move_dir: input.move_dir,
},
);
// Tick the client's LocalState (step 3) // Tick the client's LocalState (step 3)
self.state.tick(dt); self.state.tick(dt);
@ -161,28 +166,42 @@ impl Client {
self.state.read_storage().get(self.entity).cloned(), self.state.read_storage().get(self.entity).cloned(),
) { ) {
(Some(pos), Some(vel), Some(dir)) => { (Some(pos), Some(vel), Some(dir)) => {
self.postbox.send_message(ClientMsg::PlayerPhysics { pos, vel, dir }); self.postbox
}, .send_message(ClientMsg::PlayerPhysics { pos, vel, dir });
_ => {}, }
_ => {}
} }
// Update the server about the player's currently playing animation and the previous one // Update the server about the player's currently playing animation and the previous one
if let Some(animation_history) = self.state.read_storage::<comp::AnimationHistory>().get(self.entity).cloned() { if let Some(animation_history) = self
.state
.read_storage::<comp::AnimationHistory>()
.get(self.entity)
.cloned()
{
if Some(animation_history.current) != animation_history.last { if Some(animation_history.current) != animation_history.last {
self.postbox.send_message(ClientMsg::PlayerAnimation(animation_history)); self.postbox
.send_message(ClientMsg::PlayerAnimation(animation_history));
} }
} }
// Request chunks from the server // Request chunks from the server
if let Some(pos) = self.state.read_storage::<comp::phys::Pos>().get(self.entity) { if let Some(pos) = self
.state
.read_storage::<comp::phys::Pos>()
.get(self.entity)
{
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
for i in chunk_pos.x - 1..chunk_pos.x + 1 { for i in chunk_pos.x - 1..chunk_pos.x + 1 {
for j in chunk_pos.y - 1..chunk_pos.y + 1 { for j in chunk_pos.y - 1..chunk_pos.y + 1 {
for k in -1..3 { for k in -1..3 {
let key = chunk_pos + Vec3::new(i, j, k); let key = chunk_pos + Vec3::new(i, j, k);
if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) { if self.state.terrain().get_key(key).is_none()
self.postbox.send_message(ClientMsg::TerrainChunkRequest { key }); && !self.pending_chunks.contains(&key)
{
self.postbox
.send_message(ClientMsg::TerrainChunkRequest { key });
self.pending_chunks.insert(key); self.pending_chunks.insert(key);
} }
} }
@ -217,7 +236,7 @@ impl Client {
ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad), ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad),
ServerMsg::Shutdown => return Err(Error::ServerShutdown), ServerMsg::Shutdown => return Err(Error::ServerShutdown),
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong), ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
ServerMsg::Pong => {}, ServerMsg::Pong => {}
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)), ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
ServerMsg::SetPlayerEntity(uid) => self.entity = self.state.ecs().entity_from_uid(uid).unwrap(), // TODO: Don't unwrap here! ServerMsg::SetPlayerEntity(uid) => self.entity = self.state.ecs().entity_from_uid(uid).unwrap(), // TODO: Don't unwrap here!
ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package), ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
@ -226,28 +245,28 @@ impl Client {
self.state.write_component(entity, pos); self.state.write_component(entity, pos);
self.state.write_component(entity, vel); self.state.write_component(entity, vel);
self.state.write_component(entity, dir); self.state.write_component(entity, dir);
}, }
None => {}, None => {}
}, },
ServerMsg::EntityAnimation { entity, animation_history } => match self.state.ecs().entity_from_uid(entity) { ServerMsg::EntityAnimation { entity, animation_history } => match self.state.ecs().entity_from_uid(entity) {
Some(entity) => { Some(entity) => {
self.state.write_component(entity, animation_history); self.state.write_component(entity, animation_history);
}, }
None => {}, None => {}
}, },
ServerMsg::TerrainChunkUpdate { key, chunk } => { ServerMsg::TerrainChunkUpdate { key, chunk } => {
self.state.insert_chunk(key, *chunk); self.state.insert_chunk(key, *chunk);
self.pending_chunks.remove(&key); self.pending_chunks.remove(&key);
}, }
ServerMsg::StateAnswer(Ok(state)) => { ServerMsg::StateAnswer(Ok(state)) => {
self.client_state = state; self.client_state = state;
}, }
ServerMsg::StateAnswer(Err((error, state))) => { ServerMsg::StateAnswer(Err((error, state))) => {
self.client_state = state; self.client_state = state;
}, }
ServerMsg::ForceState(state) => { ServerMsg::ForceState(state) => {
self.client_state = state; self.client_state = state;
}, }
} }
} }
} else if let Some(err) = self.postbox.error() { } else if let Some(err) = self.postbox.error() {

View File

@ -1,11 +1,11 @@
use std::collections::HashMap; use crate::Error;
use specs::Entity as EcsEntity;
use common::{ use common::{
comp, comp,
msg::{ServerMsg, ClientMsg, ClientState, RequestStateError}, msg::{ClientMsg, ClientState, RequestStateError, ServerMsg},
net::PostBox, net::PostBox,
}; };
use crate::Error; use specs::Entity as EcsEntity;
use std::collections::HashMap;
pub struct Client { pub struct Client {
pub client_state: ClientState, pub client_state: ClientState,
@ -19,17 +19,16 @@ impl Client {
} }
pub fn allow_state(&mut self, new_state: ClientState) { pub fn allow_state(&mut self, new_state: ClientState) {
self.client_state = new_state; self.client_state = new_state;
self.postbox.send_message(ServerMsg::StateAnswer( self.postbox
Ok(new_state))); .send_message(ServerMsg::StateAnswer(Ok(new_state)));
} }
pub fn error_state(&mut self, error: RequestStateError) { pub fn error_state(&mut self, error: RequestStateError) {
self.postbox.send_message(ServerMsg::StateAnswer( self.postbox
Err((error, self.client_state)))); .send_message(ServerMsg::StateAnswer(Err((error, self.client_state))));
} }
pub fn force_state(&mut self, new_state: ClientState) { pub fn force_state(&mut self, new_state: ClientState) {
self.client_state = new_state; self.client_state = new_state;
self.postbox.send_message(ServerMsg::ForceState( self.postbox.send_message(ServerMsg::ForceState(new_state));
new_state));
} }
} }
@ -68,7 +67,9 @@ impl Clients {
pub fn notify_ingame(&mut self, msg: ServerMsg) { pub fn notify_ingame(&mut self, msg: ServerMsg) {
for client in self.clients.values_mut() { for client in self.clients.values_mut() {
if client.client_state == ClientState::Spectator || client.client_state == ClientState::Character { if client.client_state == ClientState::Spectator
|| client.client_state == ClientState::Character
{
client.notify(msg.clone()); client.notify(msg.clone());
} }
} }
@ -84,8 +85,10 @@ impl Clients {
pub fn notify_ingame_except(&mut self, except_entity: EcsEntity, msg: ServerMsg) { pub fn notify_ingame_except(&mut self, except_entity: EcsEntity, msg: ServerMsg) {
for (entity, client) in self.clients.iter_mut() { for (entity, client) in self.clients.iter_mut() {
if (client.client_state == ClientState::Spectator || client.client_state == ClientState::Character) if (client.client_state == ClientState::Spectator
&& *entity != except_entity { || client.client_state == ClientState::Character)
&& *entity != except_entity
{
client.notify(msg.clone()); client.notify(msg.clone());
} }
} }

View File

@ -7,7 +7,6 @@ use common::{comp, msg::ServerMsg};
use specs::{join::Join, Entity as EcsEntity}; use specs::{join::Join, Entity as EcsEntity};
use vek::*; use vek::*;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use scan_fmt::scan_fmt; use scan_fmt::scan_fmt;
/// Struct representing a command that a user can run from server chat /// Struct representing a command that a user can run from server chat

View File

@ -1,21 +1,24 @@
#![feature(drain_filter)] #![feature(drain_filter)]
pub mod client; pub mod client;
pub mod cmd;
pub mod error; pub mod error;
pub mod input; pub mod input;
pub mod cmd;
// Reexports // Reexports
pub use crate::{error::Error, input::Input}; pub use crate::{error::Error, input::Input};
use crate::{client::{Client, Clients}, cmd::CHAT_COMMANDS}; use crate::{
client::{Client, Clients},
cmd::CHAT_COMMANDS,
};
use common::{ use common::{
comp, comp,
msg::{ClientState, ClientMsg, ServerMsg, RequestStateError}, comp::character::Animation,
msg::{ClientMsg, ClientState, RequestStateError, ServerMsg},
net::PostOffice, net::PostOffice,
state::{State, Uid}, state::{State, Uid},
terrain::TerrainChunk, terrain::TerrainChunk,
comp::character::Animation,
}; };
use specs::{ use specs::{
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder, join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
@ -115,7 +118,12 @@ impl Server {
.with(character) .with(character)
} }
pub fn create_player_character(state: &mut State, entity: EcsEntity, client: &mut Client, character: comp::Character) { pub fn create_player_character(
state: &mut State,
entity: EcsEntity,
client: &mut Client,
character: comp::Character,
) {
state.write_component(entity, character); state.write_component(entity, character);
state.write_component(entity, comp::phys::Pos(Vec3::zero())); state.write_component(entity, comp::phys::Pos(Vec3::zero()));
state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Vel(Vec3::zero()));
@ -124,10 +132,13 @@ impl Server {
state.write_component(entity, comp::phys::ForceUpdate); state.write_component(entity, comp::phys::ForceUpdate);
// Set initial animation // Set initial animation
state.write_component(entity, comp::AnimationHistory { state.write_component(
last: None, entity,
current: Animation::Idle comp::AnimationHistory {
}); last: None,
current: Animation::Idle,
},
);
// Tell the client his request was successful // Tell the client his request was successful
client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character))); client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character)));
@ -223,17 +234,10 @@ impl Server {
// (All components Sphynx tracks) // (All components Sphynx tracks)
client.notify(ServerMsg::InitialSync { client.notify(ServerMsg::InitialSync {
ecs_state: self.state.ecs().gen_state_package(), ecs_state: self.state.ecs().gen_state_package(),
entity_uid: self.state entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(),
.ecs()
.uid_from_entity(entity)
.unwrap()
.into(),
}); });
self.clients.add( self.clients.add(entity, client);
entity,
client,
);
frontend_events.push(Event::ClientConnected { entity }); frontend_events.push(Event::ClientConnected { entity });
} }
@ -294,25 +298,26 @@ impl Server {
}, },
ClientMsg::Chat(msg) => match client.client_state { ClientMsg::Chat(msg) => match client.client_state {
ClientState::Connected => client.error_state(RequestStateError::Impossible), ClientState::Connected => client.error_state(RequestStateError::Impossible),
ClientState::Registered | ClientState::Spectator | ClientState::Character ClientState::Registered
=> new_chat_msgs.push((entity, msg)), | ClientState::Spectator
| ClientState::Character => new_chat_msgs.push((entity, msg)),
}, },
ClientMsg::PlayerAnimation(animation_history) => match client.client_state { ClientMsg::PlayerAnimation(animation_history) => match client.client_state {
ClientState::Character => state.write_component(entity, animation_history), ClientState::Character => state.write_component(entity, animation_history),
// Only characters can send animations // Only characters can send animations
_ => client.error_state(RequestStateError::Impossible), _ => client.error_state(RequestStateError::Impossible),
}, }
ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state { ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state {
ClientState::Character => { ClientState::Character => {
state.write_component(entity, pos); state.write_component(entity, pos);
state.write_component(entity, vel); state.write_component(entity, vel);
state.write_component(entity, dir); state.write_component(entity, dir);
}, }
// Only characters send their position // Only characters send their position
_ => client.error_state(RequestStateError::Impossible), _ => client.error_state(RequestStateError::Impossible),
}, },
ClientMsg::TerrainChunkRequest { key } => match client.client_state { ClientMsg::TerrainChunkRequest { key } => match client.client_state {
ClientState::Connected | ClientState::Registered => { ClientState::Connected | ClientState::Registered => {
client.error_state(RequestStateError::Impossible); client.error_state(RequestStateError::Impossible);
} }
ClientState::Spectator | ClientState::Character => { ClientState::Spectator | ClientState::Character => {
@ -323,11 +328,11 @@ impl Server {
}),*/ }),*/
None => requested_chunks.push(key), None => requested_chunks.push(key),
} }
}, }
} },
// Always possible // Always possible
ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong), ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
ClientMsg::Pong => {}, ClientMsg::Pong => {}
ClientMsg::Disconnect => disconnect = true, ClientMsg::Disconnect => disconnect = true,
} }
} }
@ -343,8 +348,10 @@ impl Server {
if disconnect { if disconnect {
disconnected_clients.push(entity); disconnected_clients.push(entity);
client.postbox.send_message(ServerMsg::StateAnswer( client.postbox.send_message(ServerMsg::StateAnswer(Err((
Err((RequestStateError::Impossible, ClientState::Connected)))); RequestStateError::Impossible,
ClientState::Connected,
))));
true true
} else { } else {
false false
@ -359,12 +366,7 @@ impl Server {
self.process_chat_cmd(entity, argv); self.process_chat_cmd(entity, argv);
} else { } else {
self.clients.notify_registered(ServerMsg::Chat( self.clients.notify_registered(ServerMsg::Chat(
match self match self.state.ecs().read_storage::<comp::Player>().get(entity) {
.state
.ecs()
.read_storage::<comp::Player>()
.get(entity)
{
Some(player) => format!("[{}] {}", &player.alias, msg), Some(player) => format!("[{}] {}", &player.alias, msg),
None => format!("[<anon>] {}", msg), None => format!("[<anon>] {}", msg),
}, },
@ -404,7 +406,9 @@ impl Server {
&state.ecs().entities(), &state.ecs().entities(),
&state.ecs().read_storage::<common::state::Uid>(), &state.ecs().read_storage::<common::state::Uid>(),
&state.ecs().read_storage::<comp::AnimationHistory>(), &state.ecs().read_storage::<comp::AnimationHistory>(),
).join() { )
.join()
{
// AnimationHistory // AnimationHistory
client.postbox.send_message(ServerMsg::EntityAnimation { client.postbox.send_message(ServerMsg::EntityAnimation {
entity: uid.into(), entity: uid.into(),
@ -419,7 +423,8 @@ impl Server {
/// Sync client states with the most up to date information /// Sync client states with the most up to date information
fn sync_clients(&mut self) { fn sync_clients(&mut self) {
// Sync 'logical' state using Sphynx // Sync 'logical' state using Sphynx
self.clients.notify_registered(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package())); self.clients
.notify_registered(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package()));
// Sync 'physical' state // Sync 'physical' state
for (entity, &uid, &pos, &vel, &dir, force_update) in ( for (entity, &uid, &pos, &vel, &dir, force_update) in (
@ -429,7 +434,9 @@ impl Server {
&self.state.ecs().read_storage::<comp::phys::Vel>(), &self.state.ecs().read_storage::<comp::phys::Vel>(),
&self.state.ecs().read_storage::<comp::phys::Dir>(), &self.state.ecs().read_storage::<comp::phys::Dir>(),
self.state.ecs().read_storage::<comp::phys::ForceUpdate>().maybe(), self.state.ecs().read_storage::<comp::phys::ForceUpdate>().maybe(),
).join() { )
.join()
{
let msg = ServerMsg::EntityPhysics { let msg = ServerMsg::EntityPhysics {
entity: uid.into(), entity: uid.into(),
pos, pos,
@ -448,23 +455,30 @@ impl Server {
&self.state.ecs().entities(), &self.state.ecs().entities(),
&self.state.ecs().read_storage::<Uid>(), &self.state.ecs().read_storage::<Uid>(),
&self.state.ecs().read_storage::<comp::AnimationHistory>(), &self.state.ecs().read_storage::<comp::AnimationHistory>(),
).join() { )
.join()
{
// Check if we need to sync // Check if we need to sync
if Some(animation_history.current) == animation_history.last { if Some(animation_history.current) == animation_history.last {
continue; continue;
} }
self.clients.notify_ingame_except(entity, ServerMsg::EntityAnimation { self.clients.notify_ingame_except(
entity: uid.into(), entity,
animation_history, ServerMsg::EntityAnimation {
}); entity: uid.into(),
animation_history,
},
);
} }
// Update animation last/current state // Update animation last/current state
for (entity, mut animation_history) in ( for (entity, mut animation_history) in (
&self.state.ecs().entities(), &self.state.ecs().entities(),
&mut self.state.ecs().write_storage::<comp::AnimationHistory>() &mut self.state.ecs().write_storage::<comp::AnimationHistory>(),
).join() { )
.join()
{
animation_history.last = Some(animation_history.current); animation_history.last = Some(animation_history.current);
} }