From 1d0072e19569c846777e966f7d54c611861d5197 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 14 Apr 2019 21:30:27 +0100 Subject: [PATCH 1/2] Fixed physics sync Former-commit-id: 86d3af46c69f6566f4cab8d93ecf27636a9563cf --- client/src/lib.rs | 66 ++++++++++++++++++++++------------------ common/src/comp/phys.rs | 11 ++++++- common/src/msg/server.rs | 11 ++++++- common/src/state.rs | 11 +++++-- server/src/lib.rs | 39 ++++++++++++++++++++++-- voxygen/src/scene/mod.rs | 15 ++++----- voxygen/src/window.rs | 4 +-- 7 files changed, 108 insertions(+), 49 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index a2e3648bea..a1c1450023 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -40,7 +40,7 @@ pub struct Client { tick: u64, state: State, - player: Option, + player: EcsEntity, view_distance: u64, pending_chunks: HashSet>, @@ -68,7 +68,7 @@ impl Client { let (state, player) = match postbox.next_message() { Some(ServerMsg::Handshake { ecs_state, player_entity }) => { let mut state = State::from_state_package(ecs_state); - let player_entity = state.ecs().entity_from_uid(player_entity); + let player_entity = state.ecs().entity_from_uid(player_entity).ok_or(Error::ServerWentMad)?; (state, player_entity) }, _ => return Err(Error::ServerWentMad), @@ -107,7 +107,7 @@ impl Client { /// Get the player entity #[allow(dead_code)] - pub fn player(&self) -> Option { + pub fn player(&self) -> EcsEntity { self.player } @@ -149,13 +149,17 @@ impl Client { }); // Step 1 - if let Some(ecs_entity) = self.player { + if + self.state.read_storage::().get(self.player).is_some() && + self.state.read_storage::().get(self.player).is_some() && + self.state.read_storage::().get(self.player).is_some() == true + { // TODO: remove this const PLAYER_VELOCITY: f32 = 100.0; // TODO: Set acceleration instead - self.state.write_component(ecs_entity, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY) * 0.1)); + self.state.write_component(self.player, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY) * 0.1)); if input.move_dir.magnitude() > 0.01 { - self.state.write_component(ecs_entity, comp::phys::Dir(input.move_dir.normalized().into())); + self.state.write_component(self.player, comp::phys::Dir(input.move_dir.normalized().into())); } } @@ -163,32 +167,28 @@ impl Client { self.state.tick(dt); // Update the server about the player's physics attributes - if let Some(ecs_entity) = self.player { - match ( - self.state.read_storage().get(ecs_entity).cloned(), - self.state.read_storage().get(ecs_entity).cloned(), - self.state.read_storage().get(ecs_entity).cloned(), - ) { - (Some(pos), Some(vel), Some(dir)) => { - self.postbox.send_message(ClientMsg::PlayerPhysics { pos, vel, dir }); - }, - _ => {}, - } + match ( + self.state.read_storage().get(self.player).cloned(), + self.state.read_storage().get(self.player).cloned(), + self.state.read_storage().get(self.player).cloned(), + ) { + (Some(pos), Some(vel), Some(dir)) => { + self.postbox.send_message(ClientMsg::PlayerPhysics { pos, vel, dir }); + }, + _ => {}, } // Request chunks from the server - if let Some(player_entity) = self.player { - if let Some(pos) = self.state.read_storage::().get(player_entity) { - let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); + if let Some(pos) = self.state.read_storage::().get(self.player) { + let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); - for i in chunk_pos.x - 0..chunk_pos.x + 1 { - for j in chunk_pos.y - 0..chunk_pos.y + 1 { - for k in 0..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 }); - self.pending_chunks.insert(key); - } + 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 }); + self.pending_chunks.insert(key); } } } @@ -224,8 +224,16 @@ impl Client { ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong), ServerMsg::Pong => {}, ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)), - ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here! + ServerMsg::SetPlayerEntity(uid) => self.player = 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::EntityPhysics { entity, pos, vel, dir } => match self.state.ecs().entity_from_uid(entity) { + Some(entity) => { + self.state.write_component(entity, pos); + self.state.write_component(entity, vel); + self.state.write_component(entity, dir); + }, + None => {}, + }, ServerMsg::TerrainChunkUpdate { key, chunk } => { self.state.insert_chunk(key, *chunk); self.pending_chunks.remove(&key); diff --git a/common/src/comp/phys.rs b/common/src/comp/phys.rs index 20e2b59192..b71ab214d3 100644 --- a/common/src/comp/phys.rs +++ b/common/src/comp/phys.rs @@ -1,4 +1,4 @@ -use specs::{Component, VecStorage, FlaggedStorage}; +use specs::{Component, VecStorage, FlaggedStorage, NullStorage}; use vek::*; // Pos @@ -27,3 +27,12 @@ pub struct Dir(pub Vec3); impl Component for Dir { type Storage = FlaggedStorage>; } + +// Dir + +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] +pub struct ForceUpdate; + +impl Component for ForceUpdate { + type Storage = NullStorage; +} diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index 2f852072bf..e75a69d34f 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -1,5 +1,8 @@ use vek::*; -use crate::terrain::TerrainChunk; +use crate::{ + comp, + terrain::TerrainChunk, +}; use super::EcsPacket; #[derive(Clone, Serialize, Deserialize)] @@ -14,6 +17,12 @@ pub enum ServerMsg { Chat(String), SetPlayerEntity(u64), EcsSync(sphynx::SyncPackage), + EntityPhysics { + entity: u64, + pos: comp::phys::Pos, + vel: comp::phys::Vel, + dir: comp::phys::Dir, + }, TerrainChunkUpdate { key: Vec3, chunk: Box, diff --git a/common/src/state.rs b/common/src/state.rs index 6c7a0ba9b9..480928f800 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -1,3 +1,6 @@ +// Reexports +pub use sphynx::Uid; + use std::{ time::Duration, collections::HashSet, @@ -90,12 +93,14 @@ impl State { // Create a new Sphynx ECS world fn setup_sphynx_world(ecs: &mut sphynx::World) { // Register synced components - ecs.register_synced::(); - ecs.register_synced::(); - ecs.register_synced::(); ecs.register_synced::(); ecs.register_synced::(); + // Register unsynched (or synced by other means) components + ecs.internal_mut().register::(); + ecs.internal_mut().register::(); + ecs.internal_mut().register::(); + // Register resources used by the ECS ecs.internal_mut().add_resource(TimeOfDay(0.0)); ecs.internal_mut().add_resource(Time(0.0)); diff --git a/server/src/lib.rs b/server/src/lib.rs index 8f9c7d5b80..3a2316adf3 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -27,7 +27,7 @@ use vek::*; use threadpool::ThreadPool; use common::{ comp, - state::State, + state::{State, Uid}, net::PostOffice, msg::{ServerMsg, ClientMsg}, terrain::TerrainChunk, @@ -73,8 +73,11 @@ impl Server { pub fn new() -> Result { let (chunk_tx, chunk_rx) = mpsc::channel(); + let mut state = State::new(); + state.ecs_mut().internal_mut().register::(); + Ok(Self { - state: State::new(), + state, world: World::new(), postoffice: PostOffice::bind(SocketAddr::from(([0; 4], 59003)))?, @@ -184,6 +187,9 @@ impl Server { .create_entity_synced() .build(); + // Make sure the entity gets properly created + self.state.ecs_mut().internal_mut().maintain(); + self.clients.add(entity, Client { state: ClientState::Connecting, postbox, @@ -229,6 +235,7 @@ impl Server { if let Some(character) = character { state.write_component(entity, character); } + state.write_component(entity, comp::phys::ForceUpdate); client.state = ClientState::Connected; @@ -303,7 +310,7 @@ impl Server { // Handle client disconnects for entity in disconnected_clients { - state.ecs_mut().delete_entity_synced(entity); + state.ecs_mut().delete_entity_synced(entity).unwrap(); frontend_events.push(Event::ClientDisconnected { entity, @@ -320,7 +327,33 @@ 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_connected(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package())); + + // Sync 'physical' state + for (entity, &uid, &pos, &vel, &dir, force_update) in ( + &self.state.ecs().internal().entities(), + &self.state.ecs().internal().read_storage::(), + &self.state.ecs().internal().read_storage::(), + &self.state.ecs().internal().read_storage::(), + &self.state.ecs().internal().read_storage::(), + self.state.ecs().internal().read_storage::().maybe(), + ).join() { + let msg = ServerMsg::EntityPhysics { + entity: uid.into(), + pos, + vel, + dir, + }; + + match force_update { + Some(_) => self.clients.notify_connected(msg), + None => self.clients.notify_connected_except(entity, msg), + } + } + + // Remove all force flags + self.state.ecs_mut().internal_mut().write_storage::().clear(); } pub fn generate_chunk(&mut self, key: Vec3) { diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 55a08d6a79..216601114a 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -109,15 +109,12 @@ impl Scene { pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) { // Get player position let player_pos = client - .player() - .and_then(|ent| client - .state() - .ecs() - .internal() - .read_storage::() - .get(ent) - .map(|pos| pos.0) - ) + .state() + .ecs() + .internal() + .read_storage::() + .get(client.player()) + .map(|pos| pos.0) .unwrap_or(Vec3::zero()); // Alter camera position to match player diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index eee2b3dd90..39009e4b16 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -143,9 +143,7 @@ impl Window { pub fn grab_cursor(&mut self, grab: bool) { self.cursor_grabbed = grab; self.window.hide_cursor(grab); - self.window - .grab_cursor(grab) - .expect("Failed to grab/ungrab cursor"); + let _ = self.window.grab_cursor(grab); } pub fn needs_refresh_resize(&mut self) { From 70de6cc864ace68cb3905e023228959c7c435a19 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 15 Apr 2019 00:29:26 +0100 Subject: [PATCH 2/2] Updated gitignore Former-commit-id: aa8f178f7004c61af2f0463bc1b190ae25909372 --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4c5213199c..fbac64f787 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,7 @@ # Rust /target/ -/Cargo.lock /*/target/ -/*/Cargo.lock # IntelliJ