steel_core/block_state_provider/
noise_cache.rs1use std::cell::RefCell;
2use std::sync::Arc;
3
4use steel_registry::feature::FeatureNoiseParameters;
5use steel_worldgen::noise::NormalNoise;
6
7use super::BlockStateProviderEvaluator;
8
9const MAX_CACHED_NOISES: usize = 16;
11
12thread_local! {
13 static PROVIDER_NOISES: RefCell<NoiseCache> = const { RefCell::new(NoiseCache::new()) };
14}
15
16pub(super) struct NoiseCache {
17 entries: Vec<CachedNoise>,
18 next_eviction: usize,
19}
20
21struct CachedNoise {
22 key: NoiseKey,
23 noise: Arc<NormalNoise>,
24}
25
26struct NoiseKey {
27 seed: i64,
28 base_octave: i32,
29 octave_count: i32,
30 normalize: bool,
31 base_amplitude_bits: u64,
32 amplitude_modifier_bits: Box<[u64]>,
33}
34
35impl NoiseCache {
36 const fn new() -> Self {
37 Self {
38 entries: Vec::new(),
39 next_eviction: 0,
40 }
41 }
42
43 pub(super) fn get(parameters: &FeatureNoiseParameters, seed: i64) -> Arc<NormalNoise> {
44 PROVIDER_NOISES.with_borrow_mut(|cache| cache.get_or_create(parameters, seed))
45 }
46
47 fn get_or_create(
48 &mut self,
49 parameters: &FeatureNoiseParameters,
50 seed: i64,
51 ) -> Arc<NormalNoise> {
52 if let Some(entry) = self
53 .entries
54 .iter()
55 .find(|entry| entry.key.matches(parameters, seed))
56 {
57 return Arc::clone(&entry.noise);
58 }
59
60 let noise = Arc::new(BlockStateProviderEvaluator::normal_noise(parameters, seed));
61 let entry = CachedNoise {
62 key: NoiseKey::new(parameters, seed),
63 noise: Arc::clone(&noise),
64 };
65
66 if self.entries.len() < MAX_CACHED_NOISES {
67 self.entries.push(entry);
68 } else {
69 self.entries[self.next_eviction] = entry;
70 self.next_eviction = (self.next_eviction + 1) % MAX_CACHED_NOISES;
71 }
72
73 noise
74 }
75}
76
77impl NoiseKey {
78 fn new(parameters: &FeatureNoiseParameters, seed: i64) -> Self {
79 Self {
80 seed,
81 base_octave: parameters.base_octave,
82 octave_count: parameters.octave_count,
83 normalize: parameters.normalize,
84 base_amplitude_bits: parameters.base_amplitude.to_bits(),
85 amplitude_modifier_bits: parameters
86 .amplitude_modifiers
87 .iter()
88 .map(|value| value.to_bits())
89 .collect(),
90 }
91 }
92
93 fn matches(&self, parameters: &FeatureNoiseParameters, seed: i64) -> bool {
94 self.seed == seed
95 && self.base_octave == parameters.base_octave
96 && self.octave_count == parameters.octave_count
97 && self.normalize == parameters.normalize
98 && self.base_amplitude_bits == parameters.base_amplitude.to_bits()
99 && self.amplitude_modifier_bits.iter().copied().eq(parameters
100 .amplitude_modifiers
101 .iter()
102 .map(|value| value.to_bits()))
103 }
104}