diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index d7705dd6de..233f83d8a6 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -34,7 +34,7 @@ impl<'a> BlockGen<'a> { pub fn sample_column<'b>( column_gen: &ColumnGen<'a>, - cache: &'b mut SmallCache>>, + cache: &'b mut SmallCache, Option>>, wpos: Vec2, index: IndexRef<'a>, calendar: Option<&'a Calendar>, diff --git a/world/src/index.rs b/world/src/index.rs index 5fdaa6bff9..fc8fcd9497 100644 --- a/world/src/index.rs +++ b/world/src/index.rs @@ -9,7 +9,7 @@ use common::{ trade::{SiteId, SitePrices}, }; use core::ops::Deref; -use noise::{Fbm, Seedable, SuperSimplex}; +use noise::{Fbm, Seedable, SuperSimplex, MultiFractal}; use std::sync::Arc; const WORLD_COLORS_MANIFEST: &str = "world.style.colors"; @@ -144,7 +144,7 @@ impl Noise { Self { cave_nz: SuperSimplex::new().set_seed(seed + 0), scatter_nz: SuperSimplex::new().set_seed(seed + 1), - cave_fbm_nz: Fbm::new().set_seed(seed + 2), + cave_fbm_nz: Fbm::new().set_seed(seed + 2).set_octaves(5), } } } diff --git a/world/src/layer/cave.rs b/world/src/layer/cave.rs index b35e9bd655..e0350aef41 100644 --- a/world/src/layer/cave.rs +++ b/world/src/layer/cave.rs @@ -3,7 +3,8 @@ use super::scatter::close; use crate::{ site::SiteKind, util::{ - sampler::Sampler, FastNoise2d, RandomField, RandomPerm, StructureGen2d, LOCALITY, SQUARE_4, + sampler::Sampler, FastNoise2d, RandomField, RandomPerm, SmallCache, StructureGen2d, + LOCALITY, SQUARE_4, }, Canvas, CanvasInfo, ColumnSample, Land, }; @@ -20,7 +21,6 @@ use noise::NoiseFn; use rand::prelude::*; use std::{ cmp::Ordering, - collections::HashMap, f64::consts::PI, ops::{Add, Mul, Range, Sub}, }; @@ -453,7 +453,7 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) { .max_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)) .unwrap_or(0.0) .clamp(0.0, 1.0); - let mut structure_cache = HashMap::new(); + let mut structure_cache = SmallCache::default(); canvas.foreach_col(|canvas, wpos2d, col| { let tunnel_bounds = tunnel_bounds_at_from(wpos2d, &info, &land, tunnels.iter().copied()) @@ -549,7 +549,7 @@ fn write_column( tunnel: Tunnel, dimensions: (f32, f32, f32), giant_tree_factor: f32, - structure_cache: &mut HashMap<(Vec3, Vec2), Option>, + structure_cache: &mut SmallCache, Option>, rng: &mut R, ) { let info = canvas.info(); @@ -681,9 +681,8 @@ fn write_column( let mut get_structure = |wpos: Vec3, dynamic_rng: &mut R| { for (wpos2d, seed) in StructureGen2d::new(34537, 24, 8).get(wpos.xy()) { - let structure = if let Some(structure) = structure_cache - .entry((tunnel.a.wpos.with_z(tunnel.a.depth), wpos2d)) - .or_insert_with(|| { + let structure = if let Some(structure) = + structure_cache.get(wpos2d.with_z(tunnel.a.depth), |_| { let mut rng = RandomPerm::new(seed); let (z_range, horizontal, vertical, _) = tunnel.z_range_at(wpos2d.map(|e| e as f64 + 0.5), info)?; diff --git a/world/src/util/small_cache.rs b/world/src/util/small_cache.rs index 2246d5b932..4a850b952c 100644 --- a/world/src/util/small_cache.rs +++ b/world/src/util/small_cache.rs @@ -1,23 +1,22 @@ use arr_macro::arr; -use vek::*; -fn calc_idx(v: Vec2) -> usize { - let mut x = v.x as u32; - let mut y = v.y as u32; - x = x.wrapping_mul(0x6eed0e9d); - y = y.wrapping_mul(0x2f72b421); - (x ^ y) as usize +fn calc_idx(v: impl Iterator) -> usize { + let mut r = 0; + for (e, h) in v.zip([0x6eed0e9d, 0x2f72b421, 0x18132f72, 0x891e2fba].into_iter()) { + r ^= (e as u32).wrapping_mul(h); + } + r as usize } // NOTE: Use 128 if TerrainChunkSize::RECT_SIZE.x = 128. const CACHE_LEN: usize = 32; -pub struct SmallCache { - index: [Option>; CACHE_LEN + 9], +pub struct SmallCache { + index: [Option; CACHE_LEN + 9], data: [V; CACHE_LEN + 9], random: u32, } -impl Default for SmallCache { +impl Default for SmallCache { fn default() -> Self { Self { index: [None; CACHE_LEN + 9], @@ -26,9 +25,9 @@ impl Default for SmallCache { } } } -impl SmallCache { - pub fn get) -> V>(&mut self, key: Vec2, f: F) -> &V { - let idx = calc_idx(key) % CACHE_LEN; +impl, V: Default> SmallCache { + pub fn get V>(&mut self, key: K, f: F) -> &V { + let idx = calc_idx(key.into_iter()) % CACHE_LEN; // Search if self.index[idx].as_ref().map(|k| k == &key).unwrap_or(false) {