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