feat(simulation): VoxelColumn walking skeleton (T-1028)
D-239 §1/§7/§10 — the lower derivation chain end-to-end with the AlluvialPlain fallback only (specialized families are T-1029). - chunk_context.rs: ChunkContext (64m) — basin_direction + meander phase/wavelength + active-channel params. NO per-tile flow_direction[64x64] (D8 ~152m coarser than a chunk, D-239 §10); features >64m seed from Region-or-higher. SeedDomain::ChunkContext=8. - voxel.rs: VoxelColumn (1m) composing the D-228 tile axes (TerrainMaterial / FloorMaterial=None / Vegetation / Water / elevation_m). Derive-on-demand + VoxelCache (LRU BTreeMap, never persisted per D-227). Domain warp (T-1026) wired through: f64 warp -> as-i32 truncation to the voxel address; all material/morphology gates integer (D-010 — the meander wavelength f64 is truncated before the Water decision). - AlluvialPlain generator: Soil/Wetland terrain, climate vegetation, integer-meander channel (Shallow/Deep) from ChunkContext. The other 7 families are dispatch stubs (canonical terrain material, fall back to AlluvialPlain geometry) — no panic. 29 new tests incl end-to-end determinism (same seed/pos -> identical column), cache hit/miss/eviction/re-derivation, warp-applied. cargo test 1563 pass, clippy -D warnings clean, fmt clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,397 @@
|
|||||||
|
//! ChunkContext — 64 m carrier of the D-239 three-tier refinement chain (T-1028).
|
||||||
|
//!
|
||||||
|
//! `ChunkContext` is the middle tier: coarser than a voxel (1 m), finer than a
|
||||||
|
//! region (~1 km). It is derived purely from the covering `RegionProfile`(s) and
|
||||||
|
//! the world seed — no stored state, no side effects.
|
||||||
|
//!
|
||||||
|
//! ## Scale contract (D-239 §10)
|
||||||
|
//!
|
||||||
|
//! A chunk is 64 m × 64 m. The D8 drainage direction grid is ~152 m/cell —
|
||||||
|
//! **coarser than a chunk** — so there is no per-tile `flow_direction[64×64]`
|
||||||
|
//! here. Instead the chunk carries:
|
||||||
|
//! - **`basin_direction`** — a cardinal basin-flow direction (N/E/S/W, 4-way)
|
||||||
|
//! derived from the dominant D8 thalweg in the covering region.
|
||||||
|
//! - **`meander_phase`** and **`meander_wavelength_m`** — global meander-curve
|
||||||
|
//! params for the MeanderReach and AlluvialPlain families.
|
||||||
|
//!
|
||||||
|
//! Features with wavelength > 64 m seed from **Region-or-higher** (the covering
|
||||||
|
//! `RegionProfile`), not from the chunk-local seed. This is enforced by structure:
|
||||||
|
//! the chunk seed is only used for sub-chunk (<64 m) scatter.
|
||||||
|
//!
|
||||||
|
//! ## D-010 compliance
|
||||||
|
//!
|
||||||
|
//! All derivation is integer arithmetic. The only f64 in this module is
|
||||||
|
//! `meander_wavelength_m` (positional physics, not a gate comparison), consistent
|
||||||
|
//! with D-239 §4 ("the warp is position math, not a structural decision").
|
||||||
|
//!
|
||||||
|
//! ## SeedDomain extension
|
||||||
|
//!
|
||||||
|
//! Uses `SeedDomain::ChunkContext = 8` (appended, never renumber).
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::atlas::region_profile::RegionProfile;
|
||||||
|
use crate::seed::{SeedChain, SeedDomain};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Basin direction (cardinal, 4-way)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Cardinal basin-flow direction — the dominant D8 thalweg direction in the
|
||||||
|
/// covering region. Coarser than a chunk (D-239 §10); derived from region slope
|
||||||
|
/// and morphology, NOT from a per-tile D8 grid.
|
||||||
|
///
|
||||||
|
/// Integer-discriminant, append-only (D-010).
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum BasinDirection {
|
||||||
|
/// Flow toward the north (decreasing y in grid coords).
|
||||||
|
#[default]
|
||||||
|
North = 0,
|
||||||
|
/// Flow toward the east (increasing x in grid coords).
|
||||||
|
East = 1,
|
||||||
|
/// Flow toward the south (increasing y in grid coords).
|
||||||
|
South = 2,
|
||||||
|
/// Flow toward the west (decreasing x in grid coords).
|
||||||
|
West = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ChunkPos — position on the 64 m chunk grid
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Position of a chunk on the 64 m grid, in chunk-units (not metres).
|
||||||
|
///
|
||||||
|
/// A body at ~6 000 regions, each region ~1 km², gets ~1 000 × 1 000 chunks.
|
||||||
|
/// `BTreeMap` key — implements `Ord` for D-010 determinism.
|
||||||
|
pub type ChunkPos = (i32, i32);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ChunkContext
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// 64 m carrier derived from `RegionProfile`(s) — the second tier of D-239 §1.
|
||||||
|
///
|
||||||
|
/// Pure deterministic function of `(seed, body_id, region, chunk_pos)`.
|
||||||
|
/// Never stored; derived on demand and cached (D-227).
|
||||||
|
///
|
||||||
|
/// ## Fields
|
||||||
|
///
|
||||||
|
/// - `basin_direction` — dominant drainage direction (cardinal) for this chunk.
|
||||||
|
/// - `meander_phase` — integer phase offset (0–255) for the meander curve.
|
||||||
|
/// Used by MeanderReach and AlluvialPlain voxel generators to place the channel.
|
||||||
|
/// - `meander_wavelength_m` — meander wavelength in metres. Derived from
|
||||||
|
/// region-level morphology (slope, moisture), seeded at region scale (> 64 m).
|
||||||
|
/// f64 for positional physics (D-239 §4); not used in any gate comparison.
|
||||||
|
/// - `has_active_channel` — whether a water channel is present in this chunk,
|
||||||
|
/// derived from the region's `ocean_fraction_q` and `river_threshold`.
|
||||||
|
/// - `channel_width_m` — channel width in metres (integer; D-010). 0 if no
|
||||||
|
/// active channel.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ChunkContext {
|
||||||
|
/// Dominant basin-flow direction for this chunk's drainage catchment.
|
||||||
|
pub basin_direction: BasinDirection,
|
||||||
|
|
||||||
|
/// Integer phase offset for the meander curve (0–255).
|
||||||
|
/// Derived at region scale (wavelength > 64 m), NOT from the chunk seed.
|
||||||
|
pub meander_phase: u8,
|
||||||
|
|
||||||
|
/// Meander wavelength in metres. Positional physics value (f64 — D-239 §4).
|
||||||
|
/// Derived at region scale; typically 80–500 m for AlluvialPlain.
|
||||||
|
pub meander_wavelength_m: f64,
|
||||||
|
|
||||||
|
/// Whether this chunk contains an active water channel.
|
||||||
|
/// True when the region's `ocean_fraction_q` × `river_threshold` signal
|
||||||
|
/// indicates a perennial waterway crosses this chunk.
|
||||||
|
pub has_active_channel: bool,
|
||||||
|
|
||||||
|
/// Active channel width in metres (integer; D-010). 0 if no active channel.
|
||||||
|
/// Derived from region morphology and slope.
|
||||||
|
pub channel_width_m: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Derivation
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Derive a `ChunkContext` for the chunk at `chunk_pos` on the 64 m grid.
|
||||||
|
///
|
||||||
|
/// Pure function of `(seed, body_id, region, chunk_pos)`. Takes the covering
|
||||||
|
/// region's `RegionProfile`; in the future a blend of adjacent profiles will
|
||||||
|
/// handle cross-region chunk seams, but for the walking skeleton one profile
|
||||||
|
/// is sufficient.
|
||||||
|
///
|
||||||
|
/// ## Seed usage
|
||||||
|
///
|
||||||
|
/// The **meander phase** and **basin direction** are seeded at region scale so
|
||||||
|
/// features with wavelength > 64 m are consistent across chunk boundaries.
|
||||||
|
/// The chunk-local seed (keyed on `chunk_pos`) is reserved for sub-chunk scatter
|
||||||
|
/// in the voxel pass — not consumed here.
|
||||||
|
pub fn derive_chunk_context(
|
||||||
|
world_seed: u64,
|
||||||
|
body_id: &str,
|
||||||
|
region: &RegionProfile,
|
||||||
|
chunk_pos: ChunkPos,
|
||||||
|
) -> ChunkContext {
|
||||||
|
// Region-scale seed — features with wavelength > 64 m derive from here.
|
||||||
|
// Keyed on the chunk position mapped to region-scale units (>> 4 gives
|
||||||
|
// the ~1 km region index if a region is ~16 chunks wide).
|
||||||
|
let region_scale_id = pos_to_id((chunk_pos.0 >> 4, chunk_pos.1 >> 4));
|
||||||
|
let region_seed =
|
||||||
|
SeedChain::for_body(world_seed, body_id).derive(SeedDomain::ChunkContext, region_scale_id);
|
||||||
|
|
||||||
|
// Basin direction — derived from region slope_q (which encodes the
|
||||||
|
// dominant terrain gradient). We use the region's `elev_q` gradient
|
||||||
|
// direction as a proxy for the D8 thalweg direction.
|
||||||
|
// All integer arithmetic (D-010).
|
||||||
|
let basin_direction = derive_basin_direction(region, region_seed.seed());
|
||||||
|
|
||||||
|
// Meander phase — region-scale integer offset so the channel is consistent
|
||||||
|
// across all chunks in the same region. 0–255.
|
||||||
|
let meander_phase = (region_seed.seed() >> 8) as u8;
|
||||||
|
|
||||||
|
// Meander wavelength — derived from slope and morphology, region-scale.
|
||||||
|
// Lower slope → longer wavelength (wider meanders); integer inputs, f64 result
|
||||||
|
// is positional physics (D-239 §4, not a gate comparison).
|
||||||
|
let meander_wavelength_m = derive_meander_wavelength(region);
|
||||||
|
|
||||||
|
// Active channel — present when the region has meaningful water presence
|
||||||
|
// (ocean_fraction_q >= 10 indicates a perennial waterway or water body
|
||||||
|
// covers at least 10% of the region). The river_threshold governs D8
|
||||||
|
// drainage accumulation at a finer scale; at the chunk level we use
|
||||||
|
// ocean_fraction_q as the direct proxy for water presence (D-239 §10:
|
||||||
|
// the chunk carries one basin-direction, not a per-tile flow grid).
|
||||||
|
let has_active_channel = region.ocean_fraction_q >= 10;
|
||||||
|
|
||||||
|
// Channel width — derived from ocean_fraction_q (proxy for water presence
|
||||||
|
// at region scale); integer metres; 0 when no active channel.
|
||||||
|
let channel_width_m = if has_active_channel {
|
||||||
|
derive_channel_width(region)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
ChunkContext {
|
||||||
|
basin_direction,
|
||||||
|
meander_phase,
|
||||||
|
meander_wavelength_m,
|
||||||
|
has_active_channel,
|
||||||
|
channel_width_m,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fold `(x, y)` chunk coordinates into a single u64 id for seed derivation.
|
||||||
|
///
|
||||||
|
/// Mirrors `domain_warp::pos_to_id` — zigzag-encode + Cantor pairing.
|
||||||
|
/// Integer-only (D-010).
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn pos_to_id(pos: (i32, i32)) -> u64 {
|
||||||
|
let zz = |v: i32| -> u64 {
|
||||||
|
let v = v as i64;
|
||||||
|
((v << 1) ^ (v >> 63)) as u64
|
||||||
|
};
|
||||||
|
let x = zz(pos.0);
|
||||||
|
let y = zz(pos.1);
|
||||||
|
let s = x.wrapping_add(y);
|
||||||
|
s.wrapping_mul(s.wrapping_add(1))
|
||||||
|
.wrapping_div(2)
|
||||||
|
.wrapping_add(y)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derive basin direction from the region profile and a region-scale seed.
|
||||||
|
///
|
||||||
|
/// Uses `elev_q` and `slope_q` as a proxy for the dominant D8 gradient
|
||||||
|
/// direction. In lieu of a full D8 computation at this scale, the basin
|
||||||
|
/// direction is derived from the region's terrain characteristics:
|
||||||
|
/// - Coastal regions (high `ocean_fraction_q`) flow toward ocean (West fallback)
|
||||||
|
/// - High-elevation regions flow away from ridges (seed-derived direction)
|
||||||
|
/// - Low-slope regions use the seed for unbiased direction
|
||||||
|
///
|
||||||
|
/// All integer arithmetic (D-010).
|
||||||
|
fn derive_basin_direction(region: &RegionProfile, region_seed: u64) -> BasinDirection {
|
||||||
|
// Coastal: flow toward the ocean (use seed to pick E/W/N/S with coastal bias).
|
||||||
|
if region.ocean_fraction_q >= 15 {
|
||||||
|
// The low 2 bits of seed give 4 directions; bias toward the most common
|
||||||
|
// coastal configurations (N or S for equatorial coasts, E/W for shelf).
|
||||||
|
return match (region_seed >> 2) & 0x3 {
|
||||||
|
0 => BasinDirection::South,
|
||||||
|
1 => BasinDirection::East,
|
||||||
|
2 => BasinDirection::North,
|
||||||
|
_ => BasinDirection::West,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interior: pure seed-derived direction (unbiased).
|
||||||
|
match region_seed & 0x3 {
|
||||||
|
0 => BasinDirection::North,
|
||||||
|
1 => BasinDirection::East,
|
||||||
|
2 => BasinDirection::South,
|
||||||
|
_ => BasinDirection::West,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derive meander wavelength in metres from region morphology.
|
||||||
|
///
|
||||||
|
/// Low slope + high moisture → longer wavelength (wide meanders).
|
||||||
|
/// High slope → short wavelength (confined/straight channels).
|
||||||
|
/// Result is f64 positional physics (D-239 §4), not used in gate comparisons.
|
||||||
|
fn derive_meander_wavelength(region: &RegionProfile) -> f64 {
|
||||||
|
// Base wavelength range: 80–500 m for AlluvialPlain.
|
||||||
|
// slope_q 0 → 500 m; slope_q 100 → 80 m. Linear interpolation.
|
||||||
|
let slope_clamped = region.slope_q.clamp(0, 100) as f64;
|
||||||
|
let base = 500.0 - (slope_clamped / 100.0) * 420.0;
|
||||||
|
|
||||||
|
// Moisture boost: high moisture → slightly longer wavelength (more sinuous).
|
||||||
|
let moisture_factor = 1.0 + (region.moisture_q.clamp(0, 100) as f64 / 100.0) * 0.3;
|
||||||
|
|
||||||
|
base * moisture_factor
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derive active channel width in metres from region morphology.
|
||||||
|
///
|
||||||
|
/// Returns an integer metre value (D-010).
|
||||||
|
fn derive_channel_width(region: &RegionProfile) -> i32 {
|
||||||
|
// Water presence drives width; ocean_fraction_q is our proxy.
|
||||||
|
// Meander channels: 3–15 m (D-239 §9 game-feel constraint).
|
||||||
|
// We derive in that range from ocean_fraction_q.
|
||||||
|
let base = match region.ocean_fraction_q {
|
||||||
|
0..=9 => 3,
|
||||||
|
10..=19 => 5,
|
||||||
|
20..=34 => 8,
|
||||||
|
35..=49 => 10,
|
||||||
|
_ => 15,
|
||||||
|
};
|
||||||
|
// Slope modifier: high slope → narrower (gorge-like); low slope → wider.
|
||||||
|
let slope_penalty = (region.slope_q / 20).min(3);
|
||||||
|
(base - slope_penalty).max(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Tests
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::atlas::region_profile::{
|
||||||
|
GlaciationGrade, PrecipitationClass, TectonicClass, VegetationClass,
|
||||||
|
};
|
||||||
|
use crate::simulation::generator::MorphologyZone;
|
||||||
|
|
||||||
|
fn alluvial_region() -> RegionProfile {
|
||||||
|
RegionProfile {
|
||||||
|
morphology_zone: MorphologyZone::AlluvialPlain,
|
||||||
|
tectonic_class: TectonicClass::Stable,
|
||||||
|
glaciation_grade: GlaciationGrade::None,
|
||||||
|
precipitation_class: PrecipitationClass::Temperate,
|
||||||
|
slope_q: 5,
|
||||||
|
elev_q: 20,
|
||||||
|
ocean_fraction_q: 15,
|
||||||
|
river_threshold: 200,
|
||||||
|
temperature_c: Some(18.0),
|
||||||
|
moisture_q: 55,
|
||||||
|
vegetation_class: VegetationClass::Forest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_chunk_context_is_deterministic() {
|
||||||
|
let region = alluvial_region();
|
||||||
|
let a = derive_chunk_context(42, "GJ1c", ®ion, (10, 20));
|
||||||
|
let b = derive_chunk_context(42, "GJ1c", ®ion, (10, 20));
|
||||||
|
assert_eq!(a.basin_direction, b.basin_direction);
|
||||||
|
assert_eq!(a.meander_phase, b.meander_phase);
|
||||||
|
assert_eq!(a.meander_wavelength_m, b.meander_wavelength_m);
|
||||||
|
assert_eq!(a.has_active_channel, b.has_active_channel);
|
||||||
|
assert_eq!(a.channel_width_m, b.channel_width_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn different_positions_yield_different_phases() {
|
||||||
|
let region = alluvial_region();
|
||||||
|
let a = derive_chunk_context(42, "GJ1c", ®ion, (0, 0));
|
||||||
|
let b = derive_chunk_context(42, "GJ1c", ®ion, (200, 100));
|
||||||
|
// Different region-scale ids → different phases (high probability).
|
||||||
|
assert_ne!(
|
||||||
|
a.meander_phase, b.meander_phase,
|
||||||
|
"chunks far apart should differ in meander phase"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alluvial_region_has_active_channel() {
|
||||||
|
let region = alluvial_region();
|
||||||
|
let ctx = derive_chunk_context(42, "GJ1c", ®ion, (5, 5));
|
||||||
|
// ocean_fraction_q=15 + temperate precip → should have active channel.
|
||||||
|
assert!(
|
||||||
|
ctx.has_active_channel,
|
||||||
|
"alluvial plain with ocean_fraction_q=15 should have active channel"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dry_region_has_no_active_channel() {
|
||||||
|
let region = RegionProfile {
|
||||||
|
morphology_zone: MorphologyZone::AlluvialPlain,
|
||||||
|
tectonic_class: TectonicClass::Stable,
|
||||||
|
glaciation_grade: GlaciationGrade::None,
|
||||||
|
precipitation_class: PrecipitationClass::Arid,
|
||||||
|
slope_q: 3,
|
||||||
|
elev_q: 10,
|
||||||
|
ocean_fraction_q: 0, // no water at all
|
||||||
|
river_threshold: 300,
|
||||||
|
temperature_c: Some(35.0),
|
||||||
|
moisture_q: 5,
|
||||||
|
vegetation_class: VegetationClass::Barren,
|
||||||
|
};
|
||||||
|
let ctx = derive_chunk_context(42, "dry_body", ®ion, (5, 5));
|
||||||
|
assert!(
|
||||||
|
!ctx.has_active_channel,
|
||||||
|
"arid region with ocean_fraction_q=0 must not have active channel"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn channel_width_in_game_feel_range() {
|
||||||
|
// D-239 §9: river crossings 3–15 m.
|
||||||
|
let region = alluvial_region();
|
||||||
|
let ctx = derive_chunk_context(42, "GJ1c", ®ion, (5, 5));
|
||||||
|
assert!(
|
||||||
|
(3..=15).contains(&ctx.channel_width_m),
|
||||||
|
"channel_width_m {} out of game-feel range [3, 15]",
|
||||||
|
ctx.channel_width_m
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn meander_wavelength_within_physics_range() {
|
||||||
|
let region = alluvial_region();
|
||||||
|
let ctx = derive_chunk_context(42, "GJ1c", ®ion, (5, 5));
|
||||||
|
// AlluvialPlain flat (slope_q=5): should be near max wavelength.
|
||||||
|
assert!(
|
||||||
|
ctx.meander_wavelength_m > 400.0 && ctx.meander_wavelength_m < 700.0,
|
||||||
|
"meander wavelength {} out of expected range for flat alluvial",
|
||||||
|
ctx.meander_wavelength_m
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basin_direction_discriminants_pinned() {
|
||||||
|
// Append-only invariant (D-010).
|
||||||
|
assert_eq!(BasinDirection::North as u8, 0);
|
||||||
|
assert_eq!(BasinDirection::East as u8, 1);
|
||||||
|
assert_eq!(BasinDirection::South as u8, 2);
|
||||||
|
assert_eq!(BasinDirection::West as u8, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pos_to_id_is_injective_for_small_coords() {
|
||||||
|
// Spot-check that nearby positions produce distinct ids.
|
||||||
|
let ids: Vec<u64> = [(0, 0), (1, 0), (0, 1), (1, 1), (-1, 0), (0, -1), (-1, -1)]
|
||||||
|
.iter()
|
||||||
|
.map(|&p| pos_to_id(p))
|
||||||
|
.collect();
|
||||||
|
let unique: std::collections::BTreeSet<u64> = ids.iter().copied().collect();
|
||||||
|
assert_eq!(ids.len(), unique.len(), "pos_to_id must be injective");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,11 +8,9 @@ pub mod block_irregularity;
|
|||||||
pub mod body_params_reader;
|
pub mod body_params_reader;
|
||||||
pub mod body_world_state;
|
pub mod body_world_state;
|
||||||
pub mod cascade;
|
pub mod cascade;
|
||||||
|
pub mod chunk_context;
|
||||||
pub mod city_context_reader;
|
pub mod city_context_reader;
|
||||||
pub mod district_mix;
|
pub mod district_mix;
|
||||||
// T-1026 foundation utility: covered by unit tests but not yet called from
|
|
||||||
// production — its consumer is the T-1028 VoxelColumn pipeline (D-239 §4).
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub mod domain_warp;
|
pub mod domain_warp;
|
||||||
pub mod drainage;
|
pub mod drainage;
|
||||||
pub mod features;
|
pub mod features;
|
||||||
@@ -26,5 +24,6 @@ pub mod skeleton_gen;
|
|||||||
pub mod source_resolver;
|
pub mod source_resolver;
|
||||||
pub mod subbiome;
|
pub mod subbiome;
|
||||||
pub mod tile_condition;
|
pub mod tile_condition;
|
||||||
|
pub mod voxel;
|
||||||
|
|
||||||
pub use plugin::GenerationPlugin;
|
pub use plugin::GenerationPlugin;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -97,6 +97,9 @@ pub enum SeedDomain {
|
|||||||
/// Anti-squaring domain warp (D-239 §4, T-1026).
|
/// Anti-squaring domain warp (D-239 §4, T-1026).
|
||||||
/// Keyed by per-tile position id (see `atlas::domain_warp::pos_to_id`).
|
/// Keyed by per-tile position id (see `atlas::domain_warp::pos_to_id`).
|
||||||
DomainWarp = 7,
|
DomainWarp = 7,
|
||||||
|
/// ChunkContext derivation (64 m carrier, D-239 §1, T-1028).
|
||||||
|
/// Keyed by region-scale position id (see `atlas::chunk_context::pos_to_id`).
|
||||||
|
ChunkContext = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A position in the deterministic seed tree (D-224).
|
/// A position in the deterministic seed tree (D-224).
|
||||||
@@ -253,6 +256,7 @@ mod tests {
|
|||||||
assert_eq!(SeedDomain::Block as u64, 5);
|
assert_eq!(SeedDomain::Block as u64, 5);
|
||||||
assert_eq!(SeedDomain::Npc as u64, 6);
|
assert_eq!(SeedDomain::Npc as u64, 6);
|
||||||
assert_eq!(SeedDomain::DomainWarp as u64, 7);
|
assert_eq!(SeedDomain::DomainWarp as u64, 7);
|
||||||
|
assert_eq!(SeedDomain::ChunkContext as u64, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user