diff --git a/Cargo.lock b/Cargo.lock index 2dc5d8324d..e45c0a8754 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6275,6 +6275,7 @@ dependencies = [ "ordered-float 2.8.0", "profiling", "rand 0.8.4", + "rand_chacha 0.3.1", "rayon", "rodio", "ron", diff --git a/common/src/terrain/chonk.rs b/common/src/terrain/chonk.rs index 29240560de..a71c15f41f 100644 --- a/common/src/terrain/chonk.rs +++ b/common/src/terrain/chonk.rs @@ -69,6 +69,22 @@ impl Chonk { self.sub_chunks.iter().map(SubChunk::num_groups).sum() } + /// Iterate through the voxels in this chunk, attempting to avoid those that are unchanged (i.e: match the `below` + /// and `above` voxels). This is generally useful for performance reasons. + pub fn iter_changed(&self) -> impl Iterator, &V)> + '_ { + self.sub_chunks + .iter() + .enumerate() + .filter(|(_, sc)| sc.num_groups() > 0) + .map(move |(i, sc)| { + let z_offset = self.z_offset + i as i32 * SubChunkSize::::SIZE.z as i32; + sc + .vol_iter(Vec3::zero(), SubChunkSize::::SIZE.map(|e| e as i32)) + .map(move |(pos, vox)| (pos + Vec3::unit_z() * z_offset, vox)) + }) + .flatten() + } + // Returns the index (in self.sub_chunks) of the SubChunk that contains // layer z; note that this index changes when more SubChunks are prepended fn sub_chunk_idx(&self, z: i32) -> i32 { diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index e811c715fb..3f067730ed 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -1,8 +1,5 @@ use crate::hud::CraftingTab; -use common::{ - terrain::{BlockKind, SpriteKind, TerrainChunk}, - vol::{IntoVolIterator, RectRasterableVol}, -}; +use common::terrain::{BlockKind, SpriteKind, TerrainChunk}; use common_base::span; use rand::prelude::*; use rand_chacha::ChaCha8Rng; @@ -64,14 +61,7 @@ impl BlocksOfInterest { let mut rng = ChaCha8Rng::from_seed(thread_rng().gen()); chunk - .vol_iter( - Vec3::new(0, 0, chunk.get_min_z()), - Vec3::new( - TerrainChunk::RECT_SIZE.x as i32, - TerrainChunk::RECT_SIZE.y as i32, - chunk.get_max_z(), - ), - ) + .iter_changed() .for_each(|(pos, block)| { match block.kind() { BlockKind::Leaves if rng.gen_range(0..16) == 0 => leaves.push(pos), diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs index 02f67bde05..7c1d44d4b2 100644 --- a/world/src/layer/mod.rs +++ b/world/src/layer/mod.rs @@ -607,14 +607,6 @@ pub fn apply_caverns_to(canvas: &mut Canvas, dynamic_rng: &mut R) { .mul((cavern_height as f64 - 5.0).mul(0.15).clamped(0.0, 1.0)) .mul(32.0 + cavern_avg_height as f64 * 0.85); - let lake = info.index().noise.cave_nz - .get(wpos2d.map(|e| e as f64 * 0.01).into_array()) - .sub(0.5) - .max(0.0) - .mul(2.0) - .mul(80.0); - let lake = 0.0; - let rugged = 0.25; // How bumpy should the floor be relative to the ceiling? let cavern_bottom = (cavern_avg_alt - cavern_height * rugged) as i32; let cavern_avg_bottom = (cavern_avg_alt - ((height_range.start + height_range.end) * 0.5) * rugged) as i32; @@ -626,7 +618,7 @@ pub fn apply_caverns_to(canvas: &mut Canvas, dynamic_rng: &mut R) { let floor = stalagmite as i32; - (cavern_bottom, cavern_top, cavern_avg_bottom, cavern_avg_top, floor, lake, stalagtite) + (cavern_bottom, cavern_top, cavern_avg_bottom, cavern_avg_top, floor, stalagtite) }; let mut mushroom_cache = HashMap::new(); @@ -644,8 +636,8 @@ pub fn apply_caverns_to(canvas: &mut Canvas, dynamic_rng: &mut R) { .entry(wpos2d) .or_insert_with(|| { let mut rng = RandomPerm::new(seed); - let (cavern_bottom, _, _, _, floor, _, _) = cavern_at(wpos2d); - if rng.gen_bool(0.1) { + let (cavern_bottom, cavern_top, _, _, floor, _) = cavern_at(wpos2d); + if rng.gen_bool(0.1) && cavern_top - cavern_bottom > 32 { Some(Mushroom { pos: wpos2d.with_z(cavern_bottom + floor), stalk: rng.gen_range(8.0..26.0), @@ -684,7 +676,7 @@ pub fn apply_caverns_to(canvas: &mut Canvas, dynamic_rng: &mut R) { return Some(Block::new(BlockKind::GlowingMushroom, mushroom.head_color)); } else if rpos.z <= mushroom.stalk && rpos.xy().magnitude_squared() < stalk_radius.powi(2) { // Stalk return Some(Block::new(BlockKind::Wood, Rgb::new(50, 120, 180))); - } else if ((mushroom.stalk - 1.0)..mushroom.stalk).contains(&rpos.z) // Hanging orbs + } else if ((mushroom.stalk - 0.5)..mushroom.stalk).contains(&rpos.z) // Hanging orbs && ((head_radius * 0.5)..(head_radius * 0.8)).contains(&dist) && dynamic_rng.gen_bool(0.025) { @@ -697,7 +689,7 @@ pub fn apply_caverns_to(canvas: &mut Canvas, dynamic_rng: &mut R) { }; canvas.foreach_col(|canvas, wpos2d, _col| { - let (cavern_bottom, cavern_top, cavern_avg_bottom, cavern_avg_top, floor, lake, stalagtite) = cavern_at(wpos2d); + let (cavern_bottom, cavern_top, cavern_avg_bottom, cavern_avg_top, floor, stalagtite) = cavern_at(wpos2d); let mini_stalagtite = info.index().noise.cave_nz .get(wpos2d.map(|e| e as f64 * 0.08).into_array()) @@ -708,14 +700,13 @@ pub fn apply_caverns_to(canvas: &mut Canvas, dynamic_rng: &mut R) { let stalagtite_height = (stalagtite + mini_stalagtite) as i32; let cavern_top = cavern_top as i32; - let lower_bound = cavern_bottom - lake as i32; let mut on_ground = true; - for z in lower_bound..cavern_top { + for z in cavern_bottom..cavern_top { use SpriteKind::*; let wpos = wpos2d.with_z(z); - let block = if z < lower_bound + floor { + let block = if z < cavern_bottom + floor { Block::new(BlockKind::WeakRock, Rgb::new(110, 120, 150)) } else if z > cavern_top - stalagtite_height { if dynamic_rng.gen_bool(0.0035) { // Glowing rock in stalagtites diff --git a/world/src/lib.rs b/world/src/lib.rs index 57ebdcf10e..2ceb854cfa 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -55,6 +55,8 @@ use common_net::msg::{world_msg, WorldMapMsg}; use rand::Rng; use serde::Deserialize; use std::time::Duration; +use rand_chacha::ChaCha8Rng; +use rand::prelude::*; use vek::*; #[derive(Debug)] @@ -329,7 +331,7 @@ impl World { }; // Only use for rng affecting dynamic elements like chests and entities! - let mut dynamic_rng = rand::thread_rng(); + let mut dynamic_rng = ChaCha8Rng::from_seed(thread_rng().gen()); // Apply layers (paths, caves, etc.) let mut canvas = Canvas { @@ -365,7 +367,7 @@ impl World { entities: canvas.entities, }; - let gen_entity_pos = |dynamic_rng: &mut rand::rngs::ThreadRng| { + let gen_entity_pos = |dynamic_rng: &mut ChaCha8Rng| { let lpos2d = TerrainChunkSize::RECT_SIZE .map(|sz| dynamic_rng.gen::().rem_euclid(sz) as i32); let mut lpos = Vec3::new(