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;
// Reexports
pub use specs::Entity as EcsEntity;
pub use crate::{error::Error, input::Input};
pub use specs::join::Join;
pub use crate::{
error::Error,
input::Input,
};
pub use specs::Entity as EcsEntity;
use std::{
time::Duration,
net::SocketAddr,
collections::HashSet,
};
use vek::*;
use threadpool::ThreadPool;
use specs::Builder;
use common::{
comp,
msg::{ClientMsg, ClientState, ServerMsg},
net::PostBox,
state::State,
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
@ -51,20 +44,23 @@ pub struct Client {
impl Client {
/// Create a new `Client`.
#[allow(dead_code)]
pub fn new<A: Into<SocketAddr>>(
addr: A,
view_distance: u64,
) -> Result<Self, Error> {
pub fn new<A: Into<SocketAddr>>(addr: A, view_distance: u64) -> Result<Self, Error> {
let mut client_state = ClientState::Connected;
let mut postbox = PostBox::to(addr)?;
// Wait for initial sync
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 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)
},
}
_ => return Err(Error::ServerWentMad),
};
@ -94,15 +90,21 @@ impl Client {
/// computationally expensive operations that run outside of the main thread (i.e: threads that
/// block on I/O operations are exempt).
#[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.
#[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.
#[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
#[allow(dead_code)]
@ -147,9 +149,12 @@ impl Client {
println!("Chunk at {:?}", k);
});
self.state.write_component(self.entity, comp::Control {
move_dir: input.move_dir,
});
self.state.write_component(
self.entity,
comp::Control {
move_dir: input.move_dir,
},
);
// Tick the client's LocalState (step 3)
self.state.tick(dt);
@ -161,28 +166,42 @@ impl Client {
self.state.read_storage().get(self.entity).cloned(),
) {
(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
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 {
self.postbox.send_message(ClientMsg::PlayerAnimation(animation_history));
self.postbox
.send_message(ClientMsg::PlayerAnimation(animation_history));
}
}
// 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));
for i in chunk_pos.x - 1..chunk_pos.x + 1 {
for j in chunk_pos.y - 1..chunk_pos.y + 1 {
for k in -1..3 {
let key = chunk_pos + Vec3::new(i, j, k);
if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) {
self.postbox.send_message(ClientMsg::TerrainChunkRequest { key });
if self.state.terrain().get_key(key).is_none()
&& !self.pending_chunks.contains(&key)
{
self.postbox
.send_message(ClientMsg::TerrainChunkRequest { key });
self.pending_chunks.insert(key);
}
}
@ -217,7 +236,7 @@ impl Client {
ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad),
ServerMsg::Shutdown => return Err(Error::ServerShutdown),
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
ServerMsg::Pong => {},
ServerMsg::Pong => {}
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::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, vel);
self.state.write_component(entity, dir);
},
None => {},
}
None => {}
},
ServerMsg::EntityAnimation { entity, animation_history } => match self.state.ecs().entity_from_uid(entity) {
Some(entity) => {
self.state.write_component(entity, animation_history);
},
None => {},
}
None => {}
},
ServerMsg::TerrainChunkUpdate { key, chunk } => {
self.state.insert_chunk(key, *chunk);
self.pending_chunks.remove(&key);
},
}
ServerMsg::StateAnswer(Ok(state)) => {
self.client_state = state;
},
}
ServerMsg::StateAnswer(Err((error, state))) => {
self.client_state = state;
},
}
ServerMsg::ForceState(state) => {
self.client_state = state;
},
}
}
}
} else if let Some(err) = self.postbox.error() {

View File

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

View File

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

View File

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