From f9f434a1c244b6b3abaedc20361de6b88aa329e0 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 23 Apr 2019 15:49:14 +0100 Subject: [PATCH 01/12] Started work on worldgen Former-commit-id: 277a4b2a0a5a393c590a710aebaf62e5cce2ad1d --- client/src/lib.rs | 8 ++++---- common/src/volumes/vol_map.rs | 4 +++- server/src/lib.rs | 12 ++++++------ voxygen/src/scene/terrain.rs | 24 ++++++++++++++++-------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 1fc6a8a740..cd2b3f617c 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -147,7 +147,7 @@ impl Client { frontend_events.append(&mut self.handle_new_messages()?); self.state.terrain().iter().for_each(|(k, _)| { - println!("Chunk at {:?}", k); + //println!("Chunk at {:?}", k); }); self.state.write_component( @@ -194,9 +194,9 @@ impl Client { { 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 { + for i in chunk_pos.x - 2..chunk_pos.x + 2 { + for j in chunk_pos.y - 2..chunk_pos.y + 2 { + for k in 0..1 { let key = chunk_pos + Vec3::new(i, j, k); if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index fcf45d32cd..136ae987d2 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -73,6 +73,7 @@ impl SampleVol for VolMap { /// Note that the resultant volume does not carry forward metadata from the original chunks. fn sample(&self, range: Aabb) -> Result { // Return early if we don't have all the needed chunks that we need! + /* let min_chunk = Self::chunk_key(range.min); let max_chunk = Self::chunk_key(range.max - Vec3::one()); for x in min_chunk.x..=max_chunk.x { @@ -84,6 +85,7 @@ impl SampleVol for VolMap { } } } + */ let mut sample = Dyna::filled( range.size().map(|e| e as u32).into(), @@ -92,7 +94,7 @@ impl SampleVol for VolMap { ); for pos in sample.iter_positions() { - sample.set(pos, self.get(range.min + pos)?.clone()) + sample.set(pos, self.get(range.min + pos).map(|v| v.clone()).unwrap_or(V::empty())) .map_err(|err| VolMapErr::DynaErr(err))?; } diff --git a/server/src/lib.rs b/server/src/lib.rs index 1235b0faec..9904df0832 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -182,6 +182,7 @@ impl Server { // Fetch any generated `TerrainChunk`s and insert them into the terrain // Also, send the chunk data to anybody that is close by for (key, chunk) in self.chunk_rx.try_iter() { + println!("Generation finished {:?}", key); // Send the chunk to all nearby players for (entity, player, pos) in ( &self.state.ecs().entities(), @@ -193,12 +194,11 @@ impl Server { // TODO: Distance check // if self.state.terrain().key_pos(key) - /* + println!("Send to player {:?}", key); self.clients.notify(entity, ServerMsg::TerrainChunkUpdate { key, chunk: Box::new(chunk.clone()), }); - */ } self.state.insert_chunk(key, chunk); @@ -322,10 +322,10 @@ impl Server { } ClientState::Spectator | ClientState::Character => { match state.terrain().get_key(key) { - Some(chunk) => {} /*client.postbox.send_message(ServerMsg::TerrainChunkUpdate { - key, - chunk: Box::new(chunk.clone()), - }),*/ + Some(chunk) => client.postbox.send_message(ServerMsg::TerrainChunkUpdate { + key, + chunk: Box::new(chunk.clone()), + }), None => requested_chunks.push(key), } } diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 2c33d61d00..45c9431eb2 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -99,14 +99,22 @@ impl Terrain { // What happens if the block on the edge of a chunk gets modified? We need to spawn // a mesh worker to remesh its neighbour(s) too since their ambient occlusion and face // elision information changes too! - match self.mesh_todo.iter_mut().find(|todo| todo.pos == *pos) { - Some(todo) => todo.started_tick = current_tick, - // The chunk it's queued yet, add it to the queue - None => self.mesh_todo.push_back(ChunkMeshState { - pos: *pos, - started_tick: current_tick, - active_worker: false, - }), + for i in -1..2 { + for j in -1..2 { + for k in -1..2 { + let pos = pos + Vec3::new(i, j, k); + + match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) { + Some(todo) => todo.started_tick = current_tick, + // The chunk it's queued yet, add it to the queue + None => self.mesh_todo.push_back(ChunkMeshState { + pos, + started_tick: current_tick, + active_worker: false, + }), + } + } + } } } From 61afb98869ce88ec13af0f6435de227a17c19417 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 23 Apr 2019 19:10:00 +0100 Subject: [PATCH 02/12] Foobar Former-commit-id: adac9eea1bd685a8eee275e5a05a74c287762e22 --- voxygen/src/scene/terrain.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 45c9431eb2..d58d2f9245 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -104,14 +104,16 @@ impl Terrain { for k in -1..2 { let pos = pos + Vec3::new(i, j, k); - match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) { - Some(todo) => todo.started_tick = current_tick, - // The chunk it's queued yet, add it to the queue - None => self.mesh_todo.push_back(ChunkMeshState { - pos, - started_tick: current_tick, - active_worker: false, - }), + if client.state().terrain().get_key(pos).is_some() { + match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) { + Some(todo) => todo.started_tick = current_tick, + // The chunk it's queued yet, add it to the queue + None => self.mesh_todo.push_back(ChunkMeshState { + pos, + started_tick: current_tick, + active_worker: false, + }), + } } } } From f210de09df079391ca137b84a07ab4278445f3be Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 23 Apr 2019 23:48:31 +0100 Subject: [PATCH 03/12] Added raycasting (needs testing) and basic character terrain collision Former-commit-id: be6bfacfd28e777a64d8157fce129f8072e20b38 --- client/src/lib.rs | 6 +-- common/src/lib.rs | 2 + common/src/net/post2.rs | 8 ++-- common/src/ray.rs | 77 ++++++++++++++++++++++++++++++++++++ common/src/sys/phys.rs | 37 ++++++++++++----- common/src/vol.rs | 8 +++- server/src/lib.rs | 6 +-- voxygen/src/mesh/terrain.rs | 12 +++--- voxygen/src/scene/terrain.rs | 4 +- world/src/lib.rs | 6 +-- 10 files changed, 133 insertions(+), 33 deletions(-) create mode 100644 common/src/ray.rs diff --git a/client/src/lib.rs b/client/src/lib.rs index cd2b3f617c..64cf3059ef 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -194,10 +194,10 @@ impl Client { { let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); - for i in chunk_pos.x - 2..chunk_pos.x + 2 { - for j in chunk_pos.y - 2..chunk_pos.y + 2 { + for i in chunk_pos.x - 3..chunk_pos.x + 3 { + for j in chunk_pos.y - 3..chunk_pos.y + 3 { for k in 0..1 { - let key = chunk_pos + Vec3::new(i, j, k); + let key = Vec3::new(i, j, k); if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) { diff --git a/common/src/lib.rs b/common/src/lib.rs index 146e272351..6158f45b85 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -16,6 +16,8 @@ pub mod terrain; pub mod util; pub mod volumes; pub mod vol; +pub mod ray; + // TODO: unignore the code here, for some reason it refuses to compile here while has no problems copy-pasted elsewhere /// The networking module containing high-level wrappers of `TcpListener` and `TcpStream` (`PostOffice` and `PostBox` respectively) and data types used by both the server and client /// # Examples diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs index 9617237c8e..bb79ab3531 100644 --- a/common/src/net/post2.rs +++ b/common/src/net/post2.rs @@ -179,7 +179,7 @@ impl PostBox { } // Try getting messages from the send channel - for _ in 0..10 { + for _ in 0..100 { match send_rx.try_recv() { Ok(send_msg) => { // Serialize message @@ -209,7 +209,7 @@ impl PostBox { } // Try sending bytes through the TCP stream - for _ in 0..10 { + for _ in 0..100 { //println!("HERE! Outgoing len: {}", outgoing_chunks.len()); match outgoing_chunks.pop_front() { Some(chunk) => match stream.write_all(&chunk) { @@ -230,7 +230,7 @@ impl PostBox { } // Try receiving bytes from the TCP stream - for _ in 0..10 { + for _ in 0..100 { let mut buf = [0; 1024]; match stream.read(&mut buf) { @@ -245,7 +245,7 @@ impl PostBox { } // Try turning bytes into messages - for _ in 0..10 { + for _ in 0..100 { match incoming_buf.get(0..8) { Some(len_bytes) => { let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail diff --git a/common/src/ray.rs b/common/src/ray.rs new file mode 100644 index 0000000000..d10ee1ef3e --- /dev/null +++ b/common/src/ray.rs @@ -0,0 +1,77 @@ +use vek::*; +use crate::vol::{ + Vox, + ReadVol, +}; + +pub trait RayUntil = FnMut(&V) -> bool; + +pub struct Ray<'a, V: ReadVol, F: RayUntil> { + vol: &'a V, + from: Vec3, + to: Vec3, + until: F, + max_iter: usize, +} + +impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { + pub fn new(vol: &'a V, from: Vec3, to: Vec3, until: F) -> Self { + Self { + vol, + from, + to, + until, + max_iter: 100, + } + } + + pub fn until>(self, g: G) -> Ray<'a, V, G> { + Ray { + vol: self.vol, + from: self.from, + to: self.to, + until: g, + max_iter: self.max_iter, + } + } + + pub fn max_iter(mut self, max_iter: usize) -> Self { + self.max_iter = max_iter; + self + } + + pub fn cast(mut self) -> (f32, Result<&'a V::Vox, V::Err>) { + // TODO: Fully test this! + + const PLANCK: f32 = 0.001; + + let mut dist = 0.0; + let dir = (self.to - self.from).normalized(); + + let mut pos = self.from; + let mut ipos = pos.map(|e| e as i32); + + for _ in 0..self.max_iter { + pos = dir * dist; + ipos = pos.map(|e| e as i32); + + match self.vol + .get(ipos) + .map(|vox| (vox, (self.until)(vox))) + { + Ok((vox, true)) => return (dist, Ok(vox)), + Ok((_, false)) => {}, + Err(err) => return (dist, Err(err)), + } + + let deltas = ( + dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - + pos.map(|e| e.fract()) + ) / dir; + + dist += deltas.reduce(f32::min).max(PLANCK); + } + + (dist, self.vol.get(ipos)) + } +} diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index ab25dcaf6e..f2dd81c990 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -1,25 +1,42 @@ -// Library -use specs::{Join, Read, ReadStorage, System, WriteStorage}; - -// Crate +use vek::*; +use specs::{Join, Read, ReadStorage, System, WriteStorage, ReadExpect}; use crate::{ comp::phys::{Pos, Vel}, state::DeltaTime, + terrain::TerrainMap, + vol::{Vox, ReadVol}, }; // Basic ECS physics system pub struct Sys; +const GRAVITY: f32 = 9.81; + impl<'a> System<'a> for Sys { type SystemData = ( - WriteStorage<'a, Pos>, - ReadStorage<'a, Vel>, + ReadExpect<'a, TerrainMap>, Read<'a, DeltaTime>, + WriteStorage<'a, Pos>, + WriteStorage<'a, Vel>, ); - fn run(&mut self, (mut positions, velocities, dt): Self::SystemData) { - (&mut positions, &velocities) - .join() // this can be parallelized with par_join() - .for_each(|(pos, vel)| pos.0 += vel.0 * dt.0 as f32); + fn run(&mut self, (terrain, dt, mut positions, mut velocities): Self::SystemData) { + for (pos, vel) in (&mut positions, &mut velocities).join() { + // Gravity + vel.0.z -= GRAVITY * dt.0 as f32; + + // Movement + pos.0 += vel.0 * dt.0 as f32; + + // Basic collision with terrain + while terrain + .get(pos.0.map(|e| e as i32)) + .map(|vox| !vox.is_empty()) + .unwrap_or(false) + { + pos.0.z += 0.05; + vel.0.z = 0.0; + } + } } } diff --git a/common/src/vol.rs b/common/src/vol.rs index 5a3afdb314..76b4cbc21f 100644 --- a/common/src/vol.rs +++ b/common/src/vol.rs @@ -1,5 +1,5 @@ -// Library use vek::*; +use crate::ray::{Ray, RayUntil}; /// A voxel pub trait Vox { @@ -64,6 +64,12 @@ pub trait ReadVol: BaseVol { /// Get a reference to the voxel at the provided position in the volume. #[inline(always)] fn get(&self, pos: Vec3) -> Result<&Self::Vox, Self::Err>; + + fn ray(&self, from: Vec3, to: Vec3) -> Ray bool> + where Self: Sized + { + Ray::new(self, from, to, |vox| !vox.is_empty()) + } } /// A volume that provides the ability to sample (i.e: clone a section of) its voxel data. diff --git a/server/src/lib.rs b/server/src/lib.rs index 9904df0832..fcbab7217b 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -112,7 +112,7 @@ impl Server { self.state .ecs_mut() .create_entity_synced() - .with(comp::phys::Pos(Vec3::zero())) + .with(comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))) .with(comp::phys::Vel(Vec3::zero())) .with(comp::phys::Dir(Vec3::unit_y())) .with(character) @@ -125,7 +125,7 @@ impl Server { character: comp::Character, ) { state.write_component(entity, character); - state.write_component(entity, comp::phys::Pos(Vec3::zero())); + state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))); state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); // Make sure everything is accepted @@ -182,7 +182,6 @@ impl Server { // Fetch any generated `TerrainChunk`s and insert them into the terrain // Also, send the chunk data to anybody that is close by for (key, chunk) in self.chunk_rx.try_iter() { - println!("Generation finished {:?}", key); // Send the chunk to all nearby players for (entity, player, pos) in ( &self.state.ecs().entities(), @@ -194,7 +193,6 @@ impl Server { // TODO: Distance check // if self.state.terrain().key_pos(key) - println!("Send to player {:?}", key); self.clients.notify(entity, ServerMsg::TerrainChunkUpdate { key, chunk: Box::new(chunk.clone()), diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index d04e764e6d..d37aee94b1 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -67,7 +67,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(), + -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(), -Vec3::unit_y(), Vec3::unit_z(), -Vec3::unit_x(), @@ -80,7 +80,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_x(), + -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z(), Vec3::unit_x(), @@ -93,7 +93,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - Vec3::one() + pos.map(|e| e as f32), + -Vec3::one() + pos.map(|e| e as f32), Vec3::unit_x(), Vec3::unit_z(), -Vec3::unit_y(), @@ -106,7 +106,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(), + -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(), Vec3::unit_z(), Vec3::unit_x(), Vec3::unit_y(), @@ -119,7 +119,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - Vec3::one() + pos.map(|e| e as f32), + -Vec3::one() + pos.map(|e| e as f32), Vec3::unit_y(), Vec3::unit_x(), -Vec3::unit_z(), @@ -132,7 +132,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_z(), + -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_z(), Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z(), diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index d58d2f9245..3a99e60fb5 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -106,9 +106,9 @@ impl Terrain { if client.state().terrain().get_key(pos).is_some() { match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) { - Some(todo) => todo.started_tick = current_tick, + //Some(todo) => todo.started_tick = current_tick, // The chunk it's queued yet, add it to the queue - None => self.mesh_todo.push_back(ChunkMeshState { + _ /* None */ => self.mesh_todo.push_back(ChunkMeshState { pos, started_tick: current_tick, active_worker: false, diff --git a/world/src/lib.rs b/world/src/lib.rs index 5c9d57b42c..3a42b2e22b 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -40,8 +40,8 @@ impl World { let wpos = lpos + chunk_pos * chunk.get_size().map(|e| e as i32); let wposf = wpos.map(|e| e as f64); - let freq = 1.0 / 32.0; - let ampl = 16.0; + let freq = 1.0 / 64.0; + let ampl = 12.0; let offs = 16.0; let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl + offs; @@ -49,7 +49,7 @@ impl World { if wposf.z < height - 1.0 { stone } else { - sand + grass } } else { air From 9105bf0811b91f558287f2b94a96754e58fff689 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 24 Apr 2019 12:17:45 +0100 Subject: [PATCH 04/12] Added better terrain collisions Former-commit-id: 38de44654d8050260a19a1da6c40c0f701602f13 --- common/src/sys/phys.rs | 7 +++++-- voxygen/src/mesh/terrain.rs | 14 ++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index f2dd81c990..85f8aa6e33 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -29,13 +29,16 @@ impl<'a> System<'a> for Sys { pos.0 += vel.0 * dt.0 as f32; // Basic collision with terrain + let mut i = 0; while terrain .get(pos.0.map(|e| e as i32)) .map(|vox| !vox.is_empty()) - .unwrap_or(false) + .unwrap_or(false) && + i < 20 { - pos.0.z += 0.05; + pos.0.z += 0.01; vel.0.z = 0.0; + i += 1; } } } diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index d37aee94b1..e736d2a503 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -54,6 +54,8 @@ impl Meshable for Dyna { .filter(|pos| pos.map(|e| e >= 1).reduce_and()) .filter(|pos| pos.map2(self.get_size(), |e, sz| e < sz as i32 - 1).reduce_and()) { + let offs = pos.map(|e| e as f32 - 1.0); + if let Some(col) = self .get(pos) .ok() @@ -67,9 +69,9 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(), - -Vec3::unit_y(), + offs, Vec3::unit_z(), + Vec3::unit_y(), -Vec3::unit_x(), col, )); @@ -80,7 +82,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_x(), + offs + Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z(), Vec3::unit_x(), @@ -106,7 +108,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_y(), + offs + Vec3::unit_y(), Vec3::unit_z(), Vec3::unit_x(), Vec3::unit_y(), @@ -119,7 +121,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - -Vec3::one() + pos.map(|e| e as f32), + offs, Vec3::unit_y(), Vec3::unit_x(), -Vec3::unit_z(), @@ -132,7 +134,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - -Vec3::one() + pos.map(|e| e as f32) + Vec3::unit_z(), + offs + Vec3::unit_z(), Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z(), From c37db43580fa0ad5ed1a80506cbe1cb28d73d969 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 24 Apr 2019 18:47:11 +0200 Subject: [PATCH 05/12] Fix ray position Former-commit-id: 772d5652d44c9467d22c9c93547ac154ce3110b3 --- common/src/ray.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/common/src/ray.rs b/common/src/ray.rs index d10ee1ef3e..1c7f37628d 100644 --- a/common/src/ray.rs +++ b/common/src/ray.rs @@ -25,13 +25,10 @@ impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { } } - pub fn until>(self, g: G) -> Ray<'a, V, G> { + pub fn until(self, f: F) -> Ray<'a, V, F> { Ray { - vol: self.vol, - from: self.from, - to: self.to, - until: g, - max_iter: self.max_iter, + until: f, + ..self } } @@ -52,7 +49,7 @@ impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { let mut ipos = pos.map(|e| e as i32); for _ in 0..self.max_iter { - pos = dir * dist; + pos = self.from + dir * dist; ipos = pos.map(|e| e as i32); match self.vol From 927f3a12ba82a1b3b12c7506b3413a936c038c62 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Wed, 24 Apr 2019 19:33:04 +0200 Subject: [PATCH 06/12] Fix ray issue after max_iteration Former-commit-id: 55afdeeb0358934e3874ab3ca573e8cc71904ea1 --- common/src/ray.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/ray.rs b/common/src/ray.rs index 1c7f37628d..2017c3c53d 100644 --- a/common/src/ray.rs +++ b/common/src/ray.rs @@ -37,7 +37,7 @@ impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { self } - pub fn cast(mut self) -> (f32, Result<&'a V::Vox, V::Err>) { + pub fn cast(mut self) -> (f32, Result, V::Err>) { // TODO: Fully test this! const PLANCK: f32 = 0.001; @@ -56,7 +56,7 @@ impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { .get(ipos) .map(|vox| (vox, (self.until)(vox))) { - Ok((vox, true)) => return (dist, Ok(vox)), + Ok((vox, true)) => return (dist, Ok(Some(vox))), Ok((_, false)) => {}, Err(err) => return (dist, Err(err)), } @@ -69,6 +69,6 @@ impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { dist += deltas.reduce(f32::min).max(PLANCK); } - (dist, self.vol.get(ipos)) + (dist, Ok(None)) } } From fc8b7e975014cc02bf58a8fa1dc084cdae3fdfaf Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 25 Apr 2019 09:53:39 +0100 Subject: [PATCH 07/12] Worked on improving networking and terrain Former-commit-id: e5ce819036a01f274c1c114bcd3b50fa42858703 --- client/src/lib.rs | 6 +++--- common/src/net/post2.rs | 21 ++++++++++++--------- world/src/lib.rs | 13 +++++++++---- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 64cf3059ef..84d4c29151 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -194,9 +194,9 @@ impl Client { { let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); - for i in chunk_pos.x - 3..chunk_pos.x + 3 { - for j in chunk_pos.y - 3..chunk_pos.y + 3 { - for k in 0..1 { + 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 0..2 { let key = Vec3::new(i, j, k); if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs index bb79ab3531..0f198ba7c6 100644 --- a/common/src/net/post2.rs +++ b/common/src/net/post2.rs @@ -73,6 +73,7 @@ impl PostOffice { match self.listener.accept() { Ok((stream, sock)) => new.push(PostBox::from_stream(stream).unwrap()), Err(e) if e.kind() == io::ErrorKind::WouldBlock => break, + Err(e) if e.kind() == io::ErrorKind::Interrupted => {}, Err(e) => { self.error = Some(e.into()); break; @@ -179,7 +180,7 @@ impl PostBox { } // Try getting messages from the send channel - for _ in 0..100 { + for _ in 0..1000 { match send_rx.try_recv() { Ok(send_msg) => { // Serialize message @@ -209,7 +210,7 @@ impl PostBox { } // Try sending bytes through the TCP stream - for _ in 0..100 { + for _ in 0..1000 { //println!("HERE! Outgoing len: {}", outgoing_chunks.len()); match outgoing_chunks.pop_front() { Some(chunk) => match stream.write_all(&chunk) { @@ -230,12 +231,13 @@ impl PostBox { } // Try receiving bytes from the TCP stream - for _ in 0..100 { + for _ in 0..1000 { let mut buf = [0; 1024]; match stream.read(&mut buf) { Ok(n) => incoming_buf.extend_from_slice(&buf[0..n]), Err(e) if e.kind() == io::ErrorKind::WouldBlock => break, + Err(e) if e.kind() == io::ErrorKind::Interrupted => {}, // Worker error Err(e) => { recv_tx.send(Err(e.into())).unwrap(); @@ -245,7 +247,7 @@ impl PostBox { } // Try turning bytes into messages - for _ in 0..100 { + for _ in 0..1000 { match incoming_buf.get(0..8) { Some(len_bytes) => { let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail @@ -254,13 +256,14 @@ impl PostBox { recv_tx.send(Err(Error::InvalidMessage)).unwrap(); break 'work; } else if incoming_buf.len() >= len + 8 { - let deserialize_result = bincode::deserialize(&incoming_buf[8..len + 8]); - - if let Err(e) = &deserialize_result { - println!("DESERIALIZE ERROR: {:?}", e); + match bincode::deserialize(&incoming_buf[8..len + 8]) { + Ok(msg) => recv_tx.send(Ok(msg)).unwrap(), + Err(err) => { + println!("Invalid message: {:?}", err); + recv_tx.send(Err(err.into())).unwrap() + }, } - recv_tx.send(deserialize_result.map_err(|e| e.into())); incoming_buf = incoming_buf.split_off(len + 8); } else { break; diff --git a/world/src/lib.rs b/world/src/lib.rs index 3a42b2e22b..f8d4857c13 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -40,10 +40,15 @@ impl World { let wpos = lpos + chunk_pos * chunk.get_size().map(|e| e as i32); let wposf = wpos.map(|e| e as f64); - let freq = 1.0 / 64.0; - let ampl = 12.0; - let offs = 16.0; - let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl + offs; + let freq = 1.0 / 128.0; + let ampl = 32.0; + let small_freq = 1.0 / 16.0; + let small_ampl = 8.0; + let offs = 32.0; + let height = + perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl + + perlin_nz.get(Vec2::from(wposf * small_freq).into_array()) * small_ampl + + offs; chunk.set(lpos, if wposf.z < height { if wposf.z < height - 1.0 { From a66cc98a03222f85ed5127de99229ca1d1d17056 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 25 Apr 2019 15:16:10 +0100 Subject: [PATCH 08/12] Mildly better worldgen Former-commit-id: e8d77b75b164611ccfd144b1d6e6d6c5e396e515 --- world/src/lib.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/world/src/lib.rs b/world/src/lib.rs index f8d4857c13..8b80766b49 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -32,7 +32,8 @@ impl World { let air = Block::empty(); let stone = Block::new(1, Rgb::new(200, 220, 255)); let grass = Block::new(2, Rgb::new(50, 255, 0)); - let sand = Block::new(3, Rgb::new(180, 150, 50)); + let dirt = Block::new(3, Rgb::new(128, 90, 0)); + let sand = Block::new(4, Rgb::new(180, 150, 50)); let perlin_nz = Perlin::new(); @@ -42,20 +43,20 @@ impl World { let freq = 1.0 / 128.0; let ampl = 32.0; - let small_freq = 1.0 / 16.0; - let small_ampl = 8.0; + let small_freq = 1.0 / 32.0; + let small_ampl = 6.0; let offs = 32.0; let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl + perlin_nz.get(Vec2::from(wposf * small_freq).into_array()) * small_ampl + offs; - chunk.set(lpos, if wposf.z < height { - if wposf.z < height - 1.0 { - stone - } else { - grass - } + chunk.set(lpos, if wposf.z < height - 4.0 { + stone + } else if wposf.z < height - 1.0 { + dirt + } else if wposf.z < height { + grass } else { air }).unwrap(); From 0b0c71592c119e3f925c72969261aeecc1554736 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 25 Apr 2019 16:04:36 +0100 Subject: [PATCH 09/12] Fixed orientation issue Former-commit-id: 9fdeadb4c9a9ff55cbdeccbbf97ac32b4e9f4226 --- common/src/sys/phys.rs | 8 ++++---- voxygen/src/anim/character/idle.rs | 3 +-- voxygen/src/anim/character/run.rs | 2 +- voxygen/src/mesh/terrain.rs | 2 +- voxygen/src/scene/figure.rs | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 85f8aa6e33..55af3b389b 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -10,7 +10,7 @@ use crate::{ // Basic ECS physics system pub struct Sys; -const GRAVITY: f32 = 9.81; +const GRAVITY: f32 = 9.81 * 2.0; impl<'a> System<'a> for Sys { type SystemData = ( @@ -31,12 +31,12 @@ impl<'a> System<'a> for Sys { // Basic collision with terrain let mut i = 0; while terrain - .get(pos.0.map(|e| e as i32)) + .get(pos.0.map(|e| e.floor() as i32)) .map(|vox| !vox.is_empty()) .unwrap_or(false) && - i < 20 + i < 80 { - pos.0.z += 0.01; + pos.0.z += 0.005; vel.0.z = 0.0; i += 1; } diff --git a/voxygen/src/anim/character/idle.rs b/voxygen/src/anim/character/idle.rs index c3d335654f..a3f39dfc38 100644 --- a/voxygen/src/anim/character/idle.rs +++ b/voxygen/src/anim/character/idle.rs @@ -67,8 +67,7 @@ impl Animation for IdleAnimation { next.weapon.ori = Quaternion::rotation_x(2.5); next.weapon.scale = Vec3::one(); - - next.torso.offset = Vec3::new(0.0, 0.0, 0.0); + next.torso.offset = Vec3::new(-0.5, 0.0, 0.0); next.torso.ori = Quaternion::rotation_y(0.0); next.torso.scale = Vec3::one() / 11.0; diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs index 33a8e79b95..c548c1d83e 100644 --- a/voxygen/src/anim/character/run.rs +++ b/voxygen/src/anim/character/run.rs @@ -67,7 +67,7 @@ impl Animation for RunAnimation { next.weapon.ori = Quaternion::rotation_x(2.5); next.weapon.scale = Vec3::one(); - next.torso.offset = Vec3::new(0.0, 0.0, 0.0); + next.torso.offset = Vec3::new(-0.5, 0.0, 0.0); next.torso.ori = Quaternion::rotation_y(0.25 + wavecos * 0.1); next.torso.scale = Vec3::one() / 11.0; diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index e736d2a503..b6cd2dd67e 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -95,7 +95,7 @@ impl Meshable for Dyna { .unwrap_or(true) { mesh.push_quad(create_quad( - -Vec3::one() + pos.map(|e| e as f32), + offs, Vec3::unit_x(), Vec3::unit_z(), -Vec3::unit_y(), diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 08362b3e3f..1e2e9819db 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -257,7 +257,7 @@ impl FigureState { let mat = Mat4::::identity() * Mat4::translation_3d(pos) * - Mat4::rotation_z(dir.y.atan2(dir.x));// + f32//::consts)::PI / 2.0); + Mat4::rotation_z(-dir.x.atan2(dir.y));// + f32//::consts)::PI / 2.0); let locals = FigureLocals::new(mat); renderer.update_consts(&mut self.locals, &[locals]).unwrap(); From f136a63f69a881ca331ebdb71a276e1243a5f2d9 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 25 Apr 2019 17:52:08 +0100 Subject: [PATCH 10/12] Adjusted terrain loading and meshing performance Former-commit-id: b55800b559289bf925d56096f29c0cfbc22439d2 --- common/src/net/post2.rs | 177 ++++++++++++++++++----------------- voxygen/src/scene/figure.rs | 2 +- voxygen/src/scene/terrain.rs | 8 +- 3 files changed, 98 insertions(+), 89 deletions(-) diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs index 0f198ba7c6..b654784ecc 100644 --- a/common/src/net/post2.rs +++ b/common/src/net/post2.rs @@ -170,106 +170,113 @@ impl PostBox { let mut incoming_buf = Vec::new(); 'work: while running.load(Ordering::Relaxed) { - // Get stream errors - match stream.take_error() { - Ok(Some(e)) | Err(e) => { - recv_tx.send(Err(e.into())).unwrap(); - break 'work; - }, - Ok(None) => {}, - } - - // Try getting messages from the send channel - for _ in 0..1000 { - match send_rx.try_recv() { - Ok(send_msg) => { - // Serialize message - let mut msg_bytes = bincode::serialize(&send_msg).unwrap(); - - // Assemble into packet - let mut packet_bytes = msg_bytes - .len() - .to_le_bytes() - .as_ref() - .to_vec(); - packet_bytes.append(&mut msg_bytes); - - // Split packet into chunks - packet_bytes - .chunks(4096) - .map(|chunk| chunk.to_vec()) - .for_each(|chunk| outgoing_chunks.push_back(chunk)) - }, - Err(mpsc::TryRecvError::Empty) => break, - // Worker error - Err(e) => { - let _ = recv_tx.send(Err(e.into())); + for _ in 0..30 { + // Get stream errors + match stream.take_error() { + Ok(Some(e)) | Err(e) => { + recv_tx.send(Err(e.into())).unwrap(); break 'work; }, + Ok(None) => {}, } - } - // Try sending bytes through the TCP stream - for _ in 0..1000 { - //println!("HERE! Outgoing len: {}", outgoing_chunks.len()); - match outgoing_chunks.pop_front() { - Some(chunk) => match stream.write_all(&chunk) { - Ok(()) => {}, - Err(e) if e.kind() == io::ErrorKind::WouldBlock => { - // Return chunk to the queue to try again later - outgoing_chunks.push_front(chunk); - break; + // Try getting messages from the send channel + for _ in 0..100 { + match send_rx.try_recv() { + Ok(send_msg) => { + // Serialize message + let mut msg_bytes = bincode::serialize(&send_msg).unwrap(); + + // Assemble into packet + let mut packet_bytes = msg_bytes + .len() + .to_le_bytes() + .as_ref() + .to_vec(); + packet_bytes.append(&mut msg_bytes); + + // Split packet into chunks + packet_bytes + .chunks(4096) + .map(|chunk| chunk.to_vec()) + .for_each(|chunk| outgoing_chunks.push_back(chunk)) }, + Err(mpsc::TryRecvError::Empty) => break, + // Worker error + Err(e) => { + let _ = recv_tx.send(Err(e.into())); + break 'work; + }, + } + } + + // Try sending bytes through the TCP stream + for _ in 0..100 { + //println!("HERE! Outgoing len: {}", outgoing_chunks.len()); + match outgoing_chunks.pop_front() { + Some(mut chunk) => match stream.write(&chunk) { + Ok(n) => if n == chunk.len() {}, + Ok(n) => { + outgoing_chunks.push_front(chunk.split_off(n)); + break; + }, + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + // Return chunk to the queue to try again later + outgoing_chunks.push_front(chunk); + break; + }, + // Worker error + Err(e) => { + println!("SEND ERROR: {:?}", e); + recv_tx.send(Err(e.into())).unwrap(); + break 'work; + }, + }, + None => break, + } + } + + // Try receiving bytes from the TCP stream + for _ in 0..100 { + let mut buf = [0; 4096]; + + match stream.read(&mut buf) { + Ok(n) => incoming_buf.extend_from_slice(&buf[0..n]), + Err(e) if e.kind() == io::ErrorKind::WouldBlock => break, + Err(e) if e.kind() == io::ErrorKind::Interrupted => {}, // Worker error Err(e) => { recv_tx.send(Err(e.into())).unwrap(); break 'work; }, - }, - None => break, + } } - } - // Try receiving bytes from the TCP stream - for _ in 0..1000 { - let mut buf = [0; 1024]; + // Try turning bytes into messages + for _ in 0..100 { + match incoming_buf.get(0..8) { + Some(len_bytes) => { + let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail - match stream.read(&mut buf) { - Ok(n) => incoming_buf.extend_from_slice(&buf[0..n]), - Err(e) if e.kind() == io::ErrorKind::WouldBlock => break, - Err(e) if e.kind() == io::ErrorKind::Interrupted => {}, - // Worker error - Err(e) => { - recv_tx.send(Err(e.into())).unwrap(); - break 'work; - }, - } - } + if len > MAX_MSG_SIZE { + recv_tx.send(Err(Error::InvalidMessage)).unwrap(); + break 'work; + } else if incoming_buf.len() >= len + 8 { + match bincode::deserialize(&incoming_buf[8..len + 8]) { + Ok(msg) => recv_tx.send(Ok(msg)).unwrap(), + Err(err) => { + println!("Invalid message: {:?}", err); + recv_tx.send(Err(err.into())).unwrap() + }, + } - // Try turning bytes into messages - for _ in 0..1000 { - match incoming_buf.get(0..8) { - Some(len_bytes) => { - let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail - - if len > MAX_MSG_SIZE { - recv_tx.send(Err(Error::InvalidMessage)).unwrap(); - break 'work; - } else if incoming_buf.len() >= len + 8 { - match bincode::deserialize(&incoming_buf[8..len + 8]) { - Ok(msg) => recv_tx.send(Ok(msg)).unwrap(), - Err(err) => { - println!("Invalid message: {:?}", err); - recv_tx.send(Err(err.into())).unwrap() - }, + incoming_buf = incoming_buf.split_off(len + 8); + } else { + break; } - - incoming_buf = incoming_buf.split_off(len + 8); - } else { - break; - } - }, - None => break, + }, + None => break, + } } } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 1e2e9819db..6be0e6057a 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -257,7 +257,7 @@ impl FigureState { let mat = Mat4::::identity() * Mat4::translation_3d(pos) * - Mat4::rotation_z(-dir.x.atan2(dir.y));// + f32//::consts)::PI / 2.0); + Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0); let locals = FigureLocals::new(mat); renderer.update_consts(&mut self.locals, &[locals]).unwrap(); diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 3a99e60fb5..28ea5ffbc4 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -165,8 +165,10 @@ impl Terrain { todo.active_worker = true; }); - // Receive chunk meshes from worker threads, upload them to the GPU and then store them - while let Ok(response) = self.mesh_recv.recv_timeout(Duration::new(0, 0)) { + // Receive a chunk mesh from a worker thread, upload it to the GPU and then store it + // Only pull out one chunk per frame to avoid an unacceptable amount of blocking lag due + // to the GPU upload. That still gives us a 60 chunks / second budget to play with. + if let Ok(response) = self.mesh_recv.recv_timeout(Duration::new(0, 0)) { match self.mesh_todo.iter().find(|todo| todo.pos == response.pos) { // It's the mesh we want, insert the newly finished model into the terrain model // data structure (convert the mesh to a model first of course) @@ -180,7 +182,7 @@ impl Terrain { }, // Chunk must have been removed, or it was spawned on an old tick. Drop the mesh // since it's either out of date or no longer needed - _ => continue, + _ => {}, } } } From 5e38eee8d49c56a0e7f16d516c199c1b48e4ecaf Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 25 Apr 2019 20:08:26 +0100 Subject: [PATCH 11/12] Added chunk deletion Former-commit-id: 63c29e43c4dc28097aaf4e0ff72977c7db5cc28f --- client/src/lib.rs | 28 +++++++++++++++-------- common/src/state.rs | 11 +++++++++ server/src/lib.rs | 54 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index 84d4c29151..c68abb8083 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -146,10 +146,8 @@ impl Client { // Handle new messages from the server frontend_events.append(&mut self.handle_new_messages()?); - self.state.terrain().iter().for_each(|(k, _)| { - //println!("Chunk at {:?}", k); - }); - + // Pass character control from frontend input to the player's entity + // TODO: Only do this if the entity already has a Control component! self.state.write_component( self.entity, comp::Control { @@ -186,16 +184,28 @@ impl Client { } } - // Request chunks from the server - if let Some(pos) = self + let pos = self .state .read_storage::() .get(self.entity) - { + .cloned(); + if let Some(pos) = pos { 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 { + // Remove chunks that are too far from the player + let mut chunks_to_remove = Vec::new(); + self.state.terrain().iter().for_each(|(k, _)| { + if (chunk_pos - k).map(|e| e.abs()).reduce_max() > 3 { + chunks_to_remove.push(k); + } + }); + for key in chunks_to_remove { + self.state.remove_chunk(key); + } + + // Request chunks from the server + for i in chunk_pos.x - 1..chunk_pos.x + 2 { + for j in chunk_pos.y - 1..chunk_pos.y + 2 { for k in 0..2 { let key = Vec3::new(i, j, k); if self.state.terrain().get_key(key).is_none() diff --git a/common/src/state.rs b/common/src/state.rs index e8b4601d94..54fe252913 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -183,6 +183,17 @@ impl State { } } + /// Remove the chunk with the given key from this state's terrain, if it exists + pub fn remove_chunk(&mut self, key: Vec3) { + if self.ecs + .write_resource::() + .remove(key) + .is_some() + { + self.changes.removed_chunks.insert(key); + } + } + /// Execute a single tick, simulating the game state by the given duration. pub fn tick(&mut self, dt: Duration) { // Change the time accordingly diff --git a/server/src/lib.rs b/server/src/lib.rs index fcbab7217b..3dbc36e0b9 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -8,10 +8,20 @@ pub mod input; // Reexports pub use crate::{error::Error, input::Input}; -use crate::{ - client::{Client, Clients}, - cmd::CHAT_COMMANDS, +use std::{ + collections::HashSet, + net::SocketAddr, + sync::mpsc, + time::Duration, + i32, }; +use specs::{ + join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder, + Entity as EcsEntity, +}; +use threadpool::ThreadPool; +use vek::*; +use world::World; use common::{ comp, comp::character::Animation, @@ -20,14 +30,10 @@ use common::{ state::{State, Uid}, terrain::TerrainChunk, }; -use specs::{ - join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder, - Entity as EcsEntity, +use crate::{ + client::{Client, Clients}, + cmd::CHAT_COMMANDS, }; -use std::{collections::HashSet, net::SocketAddr, sync::mpsc, time::Duration}; -use threadpool::ThreadPool; -use vek::*; -use world::World; const CLIENT_TIMEOUT: f64 = 20.0; // Seconds @@ -187,9 +193,7 @@ impl Server { &self.state.ecs().entities(), &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), - ) - .join() - { + ).join() { // TODO: Distance check // if self.state.terrain().key_pos(key) @@ -200,6 +204,30 @@ impl Server { } self.state.insert_chunk(key, chunk); + self.pending_chunks.remove(&key); + } + + // Remove chunks that are too far from players + let mut chunks_to_remove = Vec::new(); + self.state.terrain().iter().for_each(|(k, _)| { + let mut min_dist = i32::MAX; + + // For each player with a position, calculate the distance + for (_, pos) in ( + &self.state.ecs().read_storage::(), + &self.state.ecs().read_storage::(), + ).join() { + let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); + let dist = (chunk_pos - k).map(|e| e.abs()).reduce_max(); + min_dist = min_dist.min(dist); + } + + if min_dist > 3 { + chunks_to_remove.push(k); + } + }); + for key in chunks_to_remove { + self.state.remove_chunk(key); } // Synchronise clients with the new state of the world From e4d6d96afc58e1dcf1944157d95a81f07e153df2 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 25 Apr 2019 20:25:22 +0100 Subject: [PATCH 12/12] Remove post debugging Former-commit-id: 4a82bf8b6178fb88d5a6ea93706fb4e97ac2256d --- client/src/lib.rs | 6 +++--- common/src/net/post2.rs | 3 --- server/src/lib.rs | 20 +++++++++++--------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index c68abb8083..6efe76ab0b 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -194,9 +194,9 @@ impl Client { // Remove chunks that are too far from the player let mut chunks_to_remove = Vec::new(); - self.state.terrain().iter().for_each(|(k, _)| { - if (chunk_pos - k).map(|e| e.abs()).reduce_max() > 3 { - chunks_to_remove.push(k); + self.state.terrain().iter().for_each(|(key, _)| { + if (chunk_pos - key).map(|e| e.abs()).reduce_max() > 3 { + chunks_to_remove.push(key); } }); for key in chunks_to_remove { diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs index b654784ecc..ea41ad4516 100644 --- a/common/src/net/post2.rs +++ b/common/src/net/post2.rs @@ -212,7 +212,6 @@ impl PostBox { // Try sending bytes through the TCP stream for _ in 0..100 { - //println!("HERE! Outgoing len: {}", outgoing_chunks.len()); match outgoing_chunks.pop_front() { Some(mut chunk) => match stream.write(&chunk) { Ok(n) => if n == chunk.len() {}, @@ -227,7 +226,6 @@ impl PostBox { }, // Worker error Err(e) => { - println!("SEND ERROR: {:?}", e); recv_tx.send(Err(e.into())).unwrap(); break 'work; }, @@ -265,7 +263,6 @@ impl PostBox { match bincode::deserialize(&incoming_buf[8..len + 8]) { Ok(msg) => recv_tx.send(Ok(msg)).unwrap(), Err(err) => { - println!("Invalid message: {:?}", err); recv_tx.send(Err(err.into())).unwrap() }, } diff --git a/server/src/lib.rs b/server/src/lib.rs index 3dbc36e0b9..99efa95d4f 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -194,13 +194,15 @@ impl Server { &self.state.ecs().read_storage::(), &self.state.ecs().read_storage::(), ).join() { - // TODO: Distance check - // if self.state.terrain().key_pos(key) + let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); + let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max(); - self.clients.notify(entity, ServerMsg::TerrainChunkUpdate { - key, - chunk: Box::new(chunk.clone()), - }); + if dist < 4 { + self.clients.notify(entity, ServerMsg::TerrainChunkUpdate { + key, + chunk: Box::new(chunk.clone()), + }); + } } self.state.insert_chunk(key, chunk); @@ -209,7 +211,7 @@ impl Server { // Remove chunks that are too far from players let mut chunks_to_remove = Vec::new(); - self.state.terrain().iter().for_each(|(k, _)| { + self.state.terrain().iter().for_each(|(key, _)| { let mut min_dist = i32::MAX; // For each player with a position, calculate the distance @@ -218,12 +220,12 @@ impl Server { &self.state.ecs().read_storage::(), ).join() { let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32)); - let dist = (chunk_pos - k).map(|e| e.abs()).reduce_max(); + let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max(); min_dist = min_dist.min(dist); } if min_dist > 3 { - chunks_to_remove.push(k); + chunks_to_remove.push(key); } }); for key in chunks_to_remove {