Skip to main content

steel_worldgen/density/
traits.rs

1//! Traits for dimension-specific noise generation.
2//!
3//! These traits abstract over dimension-specific types (overworld, nether, etc.)
4//! allowing generic chunk generation code to work with any dimension's transpiled
5//! density functions.
6
7use std::simd::f64x4;
8
9use crate::BlockStateId;
10use crate::random::RandomSplitter;
11use crate::surface::SurfaceRuleContext;
12use rustc_hash::FxHashMap;
13
14use super::NoiseParameters;
15
16/// Noise settings for a dimension, parsed from the datapack.
17///
18/// These are compile-time constants generated from `noise_settings` JSON files.
19pub trait NoiseSettings: Send + Sync {
20    /// Minimum Y coordinate for this dimension.
21    const MIN_Y: i32;
22    /// Total height of the world in blocks.
23    const HEIGHT: i32;
24    /// Sea level Y coordinate.
25    const SEA_LEVEL: i32;
26    /// Cell width in blocks (XZ direction).
27    const CELL_WIDTH: i32;
28    /// Cell height in blocks (Y direction).
29    const CELL_HEIGHT: i32;
30    /// Whether aquifers are enabled for this dimension.
31    const AQUIFERS_ENABLED: bool;
32    /// Whether ore veins are enabled for this dimension.
33    const ORE_VEINS_ENABLED: bool;
34    /// Whether this dimension uses Java's LCG random (true) or Xoroshiro (false).
35    const LEGACY_RANDOM_SOURCE: bool;
36
37    /// Get the default block state ID for this dimension.
38    fn default_block_id() -> BlockStateId;
39
40    /// Get the default fluid state ID for this dimension.
41    fn default_fluid_id() -> BlockStateId;
42}
43
44/// Column cache for a dimension's flat-cached density function results.
45///
46/// Stores Y-independent values that only need to be computed once per (x, z) column.
47pub trait ColumnCache: Clone + Default + Send + Sync {
48    /// The associated noises type for this cache.
49    type Noises: DimensionNoises<ColumnCache = Self>;
50
51    /// Ensure the cache is populated for the given block coordinates.
52    ///
53    /// If the cache already holds values for this column, this is a no-op.
54    fn ensure(&mut self, x: i32, z: i32, noises: &Self::Noises);
55
56    /// Pre-compute flat-cached values for all quart positions in a chunk.
57    ///
58    /// Matches vanilla's `NoiseChunk.FlatCache`: eagerly fills a 2D grid of
59    /// `(quart_size+1)²` entries (size baked in per dimension at compile time).
60    /// After this call, `ensure()` for in-bounds positions is an O(1) grid
61    /// lookup. Out-of-bounds positions fall back to on-the-fly evaluation at
62    /// raw (non-quantized) coordinates.
63    fn init_grid(&mut self, chunk_block_x: i32, chunk_block_z: i32, noises: &Self::Noises);
64}
65
66/// All noise generators and density functions for a dimension.
67///
68/// This trait abstracts over dimension-specific noise types (`OverworldNoises`,
69/// `NetherNoises`, etc.) allowing generic code to work with any dimension.
70pub trait DimensionNoises: Sized + Send + Sync {
71    /// The column cache type for this dimension.
72    type ColumnCache: ColumnCache<Noises = Self>;
73    /// The noise settings type for this dimension.
74    type Settings: NoiseSettings;
75
76    /// Create all noise generators from a world seed and its positional splitter.
77    fn create(
78        seed: u64,
79        splitter: &RandomSplitter,
80        params: &FxHashMap<String, NoiseParameters>,
81    ) -> Self;
82
83    // ── Router functions ────────────────────────────────────────────────────
84
85    /// Final density for terrain generation (positive = solid, negative = air).
86    fn router_final_density(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
87
88    /// Depth from surface (used for terrain shaping).
89    fn router_depth(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
90
91    // ── Aquifer router functions ────────────────────────────────────────────
92
93    /// Barrier noise for aquifer boundaries.
94    fn router_barrier(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
95
96    /// Fluid level floodedness for aquifers.
97    fn router_fluid_level_floodedness(
98        &self,
99        cache: &mut Self::ColumnCache,
100        x: i32,
101        y: i32,
102        z: i32,
103    ) -> f64;
104
105    /// Fluid level spread for aquifers.
106    fn router_fluid_level_spread(
107        &self,
108        cache: &mut Self::ColumnCache,
109        x: i32,
110        y: i32,
111        z: i32,
112    ) -> f64;
113
114    /// Lava placement noise for aquifers.
115    fn router_lava(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
116
117    // ── Ore vein router functions ───────────────────────────────────────────
118
119    /// Vein toggle (sign determines copper vs iron).
120    fn router_vein_toggle(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
121
122    /// Vein ridged noise for ore placement.
123    fn router_vein_ridged(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
124
125    /// Vein gap noise for ore vs filler placement.
126    fn router_vein_gap(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
127
128    // ── Climate/biome router functions (Y-independent, cached) ──────────────
129
130    /// Erosion value (cached in column cache).
131    fn router_erosion(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
132
133    /// Continentalness value (cached in column cache).
134    fn router_continentalness(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
135
136    /// Temperature value (cached in column cache).
137    fn router_temperature(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
138
139    /// Vegetation/humidity value (cached in column cache).
140    fn router_vegetation(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
141
142    /// Ridges/weirdness value (cached in column cache).
143    fn router_ridges(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f64;
144
145    /// Preliminary surface level (cached in column cache).
146    fn router_preliminary_surface_level(
147        &self,
148        cache: &mut Self::ColumnCache,
149        x: i32,
150        y: i32,
151        z: i32,
152    ) -> f64;
153
154    // ── Interpolation functions ─────────────────────────────────────────────
155
156    /// Total number of independently interpolated channels across all router
157    /// entries (`final_density` + `vein_toggle` + `vein_ridged`).
158    fn interpolated_count() -> usize;
159
160    /// Whether vein functions have interpolation channels.
161    fn vein_interp_enabled() -> bool;
162
163    /// Compute blended noise for an entire column of Y values.
164    ///
165    /// Called by `NoiseChunk::fill_slice` before iterating over Y corners.
166    /// Dimensions that use `BlendedNoise` (e.g. overworld) should override this
167    /// to SIMD-batch the blended noise computation.
168    ///
169    /// Default: no-op (fills `out` with zeros).
170    fn compute_noise_column(&self, _x: i32, _block_ys: &[i32], _z: i32, out: &mut [f64]) {
171        out.fill(0.0);
172    }
173
174    /// Evaluate the inner functions of all `Interpolated` markers at a cell corner.
175    ///
176    /// `out` must have length [`interpolated_count()`]. Each element receives
177    /// the value of one `Interpolated` marker's inner function at `(x, y, z)`.
178    /// `blended_noise_value` is the precomputed blended noise for this Y level.
179    fn fill_cell_corner_densities(
180        &self,
181        cache: &mut Self::ColumnCache,
182        x: i32,
183        y: i32,
184        z: i32,
185        blended_noise_value: f64,
186        out: &mut [f64],
187    );
188
189    /// SIMD form of [`fill_cell_corner_densities`] that batches 4 cell-corner
190    /// Y values at fixed `(x, z)`.
191    ///
192    /// `out` layout: lane-major `SoA`. Lane `i`'s `interpolated_count()` channels
193    /// occupy `out[i * interpolated_count()..(i + 1) * interpolated_count()]`.
194    /// `out` must have length `4 * interpolated_count()`.
195    ///
196    /// The default implementation calls the scalar [`fill_cell_corner_densities`]
197    /// four times. Dimensions can override with a true SIMD implementation (the
198    /// transpiled `compute_*_4x` chain) once the SIMD codegen is in place.
199    ///
200    /// [`fill_cell_corner_densities`]: Self::fill_cell_corner_densities
201    fn fill_cell_corner_densities_4x(
202        &self,
203        cache: &mut Self::ColumnCache,
204        x: i32,
205        ys: f64x4,
206        z: i32,
207        blended_noise_values: f64x4,
208        out: &mut [f64],
209    ) {
210        let interp_count = Self::interpolated_count();
211        let ys_arr = ys.to_array();
212        let blended_arr = blended_noise_values.to_array();
213        for lane in 0..4 {
214            let dst = &mut out[lane * interp_count..(lane + 1) * interp_count];
215            #[expect(
216                clippy::cast_possible_truncation,
217                reason = "block Y values are integer-valued f64s in cell-corner range"
218            )]
219            let y = ys_arr[lane] as i32;
220            self.fill_cell_corner_densities(cache, x, y, z, blended_arr[lane], dst);
221        }
222    }
223
224    /// Combine trilinearly interpolated values for `final_density`.
225    fn combine_interpolated(
226        &self,
227        cache: &mut Self::ColumnCache,
228        interpolated: &[f64],
229        x: i32,
230        y: i32,
231        z: i32,
232    ) -> f64;
233
234    /// Combine trilinearly interpolated values for `vein_toggle`.
235    fn combine_vein_toggle(
236        &self,
237        cache: &mut Self::ColumnCache,
238        interpolated: &[f64],
239        x: i32,
240        y: i32,
241        z: i32,
242    ) -> f64;
243
244    /// Combine trilinearly interpolated values for `vein_ridged`.
245    fn combine_vein_ridged(
246        &self,
247        cache: &mut Self::ColumnCache,
248        interpolated: &[f64],
249        x: i32,
250        y: i32,
251        z: i32,
252    ) -> f64;
253
254    // ── Surface rules ───────────────────────────────────────────────────────
255
256    /// Noise IDs referenced by this dimension's surface rule `NoiseThreshold`
257    /// conditions. Used to construct the `SurfaceSystem`'s condition noises.
258    fn surface_noise_ids() -> &'static [&'static str];
259
260    /// Random IDs referenced by this dimension's surface rule `VerticalGradient`
261    /// conditions. Used to construct reusable positional random factories.
262    fn surface_gradient_ids() -> &'static [&'static str];
263
264    /// Block states returned by this dimension's generated surface rules.
265    fn surface_rule_block_states() -> &'static [BlockStateId];
266
267    /// Whether the generated surface rule reads biome-dependent context.
268    fn surface_rule_uses_biome() -> bool;
269
270    /// Whether the generated surface rule reads preliminary surface level.
271    fn surface_rule_uses_preliminary_surface() -> bool;
272
273    /// Whether the generated surface rule reads surface secondary noise.
274    fn surface_rule_uses_surface_secondary() -> bool;
275
276    /// Whether the generated surface rule reads steep-column context.
277    fn surface_rule_uses_steep() -> bool;
278
279    /// Apply the transpiled surface rule at the given context position.
280    fn try_apply_surface_rule(ctx: &mut SurfaceRuleContext<'_>) -> Option<BlockStateId>;
281}