diff --git a/Cargo.lock b/Cargo.lock index 82300744e9..984e8161c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,6 +93,25 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arr_macro" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arr_macro_impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arr_macro_impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayref" version = "0.3.5" @@ -3733,6 +3752,7 @@ dependencies = [ name = "veloren-world" version = "0.3.0" dependencies = [ + "arr_macro 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "minifb 0.12.0 (git+https://github.com/emoon/rust_minifb.git)", @@ -3943,6 +3963,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +"checksum arr_macro 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d262b83f2f573121554ad6e764cd444303df85d86e5fcebc81903ddcf8dd3a97" +"checksum arr_macro_impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8decbe97ffec939e44228d91e5d0829ceb1616c6ed0984c09df164b1e7ebaafc" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum ascii 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "97be891acc47ca214468e09425d02cef3af2c94d0d82081cd02061f996802f14" diff --git a/world/Cargo.toml b/world/Cargo.toml index 6a76450eef..a558ec59c0 100644 --- a/world/Cargo.toml +++ b/world/Cargo.toml @@ -12,6 +12,7 @@ hashbrown = { version = "0.6.0", features = ["serde"] } lazy_static = "1.4.0" rand = "0.7.2" rand_chacha = "0.2.1" +arr_macro = "0.1.2" [dev-dependencies] minifb = { git = "https://github.com/emoon/rust_minifb.git" } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index a893e6f75b..bf2795383a 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -3,7 +3,7 @@ mod natural; use crate::{ column::{ColumnGen, ColumnSample}, generator::{Generator, TownGen}, - util::{HashCache, RandomField, Sampler, SamplerMut}, + util::{RandomField, Sampler, SamplerMut, SmallCache}, World, CONFIG, }; use common::{ @@ -16,7 +16,7 @@ use vek::*; pub struct BlockGen<'a> { world: &'a World, - column_cache: HashCache, Option>>, + column_cache: SmallCache>>, column_gen: ColumnGen<'a>, } @@ -24,14 +24,14 @@ impl<'a> BlockGen<'a> { pub fn new(world: &'a World, column_gen: ColumnGen<'a>) -> Self { Self { world, - column_cache: HashCache::with_capacity(64), + column_cache: SmallCache::default(), column_gen, } } fn sample_column( column_gen: &ColumnGen<'a>, - cache: &mut HashCache, Option>>, + cache: &mut SmallCache>>, wpos: Vec2, ) -> Option> { cache @@ -41,7 +41,7 @@ impl<'a> BlockGen<'a> { fn get_cliff_height( column_gen: &ColumnGen<'a>, - cache: &mut HashCache, Option>>, + cache: &mut SmallCache>>, wpos: Vec2, close_cliffs: &[(Vec2, u32); 9], cliff_hill: f32, diff --git a/world/src/block/natural.rs b/world/src/block/natural.rs index 30a5a330d0..b834c36553 100644 --- a/world/src/block/natural.rs +++ b/world/src/block/natural.rs @@ -2,7 +2,7 @@ use super::{BlockGen, StructureInfo, StructureMeta}; use crate::{ all::ForestKind, column::{ColumnGen, ColumnSample}, - util::{HashCache, RandomPerm, Sampler, UnitChooser}, + util::{RandomPerm, Sampler, SmallCache, UnitChooser}, CONFIG, }; use common::{assets, terrain::Structure}; @@ -17,7 +17,7 @@ static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F); pub fn structure_gen<'a>( column_gen: &ColumnGen<'a>, - column_cache: &mut HashCache, Option>>, + column_cache: &mut SmallCache>>, idx: usize, st_pos: Vec2, st_seed: u32, diff --git a/world/src/util/mod.rs b/world/src/util/mod.rs index 218901d903..489e3469b2 100644 --- a/world/src/util/mod.rs +++ b/world/src/util/mod.rs @@ -4,6 +4,7 @@ pub mod hash_cache; pub mod random; pub mod sampler; pub mod seed_expan; +pub mod small_cache; pub mod structure; pub mod unit_chooser; @@ -14,6 +15,7 @@ pub use self::{ hash_cache::HashCache, random::{RandomField, RandomPerm}, sampler::{Sampler, SamplerMut}, + small_cache::SmallCache, structure::StructureGen2d, unit_chooser::UnitChooser, }; diff --git a/world/src/util/small_cache.rs b/world/src/util/small_cache.rs new file mode 100644 index 0000000000..c2338f383c --- /dev/null +++ b/world/src/util/small_cache.rs @@ -0,0 +1,159 @@ +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 +} + +pub struct SmallCache { + index: [Option>; 137], + data: [V; 137], + random: u32, +} +impl Default for SmallCache { + fn default() -> Self { + Self { + index: arr![None; 137], + data: arr![V::default(); 137], + random: 1, + } + } +} +impl SmallCache { + pub fn get) -> V>(&mut self, key: Vec2, f: F) -> &V { + let idx = calc_idx(key) % 128; + + // Search + if self.index[idx].as_ref().map(|k| k == &key).unwrap_or(false) { + return &self.data[idx]; + } else if self.index[idx + 1] + .as_ref() + .map(|k| k == &key) + .unwrap_or(false) + { + return &self.data[idx + 1]; + } else if self.index[idx + 4] + .as_ref() + .map(|k| k == &key) + .unwrap_or(false) + { + return &self.data[idx + 4]; + } else if self.index[idx + 9] + .as_ref() + .map(|k| k == &key) + .unwrap_or(false) + { + return &self.data[idx + 9]; + } + // Not present so insert + for i in 0..4 { + let idx = idx + i * i; + if self.index[idx].is_none() { + self.index[idx] = Some(key.clone()); + self.data[idx] = f(key); + return &self.data[idx]; + } + } + // No space randomly remove someone + let step = super::seed_expan::diffuse(self.random) as usize % 4; + let idx = step * step + idx; + self.random = self.random.wrapping_add(1); + self.index[idx] = Some(key.clone()); + self.data[idx] = f(key); + &self.data[idx] + } +} + +/*pub struct SmallCache { + index: [Option>; 128], + data: [V; 128], + random: u32, +} +impl Default for SmallCache { + fn default() -> Self { + Self { + index: arr![None; 128], + data: arr![V::default(); 128], + random: 1, + } + } +} +impl SmallCache { + pub fn get) -> V>(&mut self, key: Vec2, f: F) -> &V { + let idx = calc_idx(key) % 32 * 4; + + // Search + if self.index[idx].as_ref().map(|k| k == &key).unwrap_or(false) { + return &self.data[idx]; + } else if self.index[idx + 1] + .as_ref() + .map(|k| k == &key) + .unwrap_or(false) + { + return &self.data[idx + 1]; + } else if self.index[idx + 2] + .as_ref() + .map(|k| k == &key) + .unwrap_or(false) + { + return &self.data[idx + 2]; + } else if self.index[idx + 3] + .as_ref() + .map(|k| k == &key) + .unwrap_or(false) + { + return &self.data[idx + 3]; + } + // Not present so insert + for i in 0..4 { + let idx = idx + i; + if self.index[idx].is_none() { + self.index[idx] = Some(key.clone()); + self.data[idx] = f(key); + return &self.data[idx]; + } + } + let idx = idx + super::seed_expan::diffuse(self.random) as usize % 4; + self.random = self.random.wrapping_add(1); + self.index[idx] = Some(key.clone()); + self.data[idx] = f(key); + &self.data[idx] + } +}*/ + +/*const ZCACHE_SIZE: usize = 32; + +#[derive(Default)] +pub struct ZestSmallCache { + index: [Option; ZCACHE_SIZE], + cache: [V; ZCACHE_SIZE], + not_cached: V, +} + +impl ZestSmallCache { + pub fn get V>(&mut self, key: K, cache: bool, f: F) -> &V { + for i in 0..ZCACHE_SIZE { + if self.index[i].as_ref().map(|k| k == &key).unwrap_or(false) { + return &self.cache[i]; + } + } + if !cache { + self.not_cached = f(key); + return &self.not_cached; + } + for i in 0..ZCACHE_SIZE { + if self.index[i].is_none() { + self.index[i] = Some(key.clone()); + self.cache[i] = f(key.clone()); + return &self.cache[i]; + } + } + self.index[0] = Some(key.clone()); + self.cache[0] = f(key); + &self.cache[0] + } +}*/