diff --git a/Core/Scripts/BLUEPRINT_FORMAT.md b/Core/Scripts/BLUEPRINT_FORMAT.md index f905988..6e3d925 100644 --- a/Core/Scripts/BLUEPRINT_FORMAT.md +++ b/Core/Scripts/BLUEPRINT_FORMAT.md @@ -59,7 +59,7 @@ Every section: `[u32 tag][u64 payload-length in bytes][payload]`. | `TDTL` / `0x4C544454` | 30 B: `u16 detailVersion` · `f32 reliefAmpM` · `f32 reliefFreqIslands` · `i32 reliefSeedOffset` · `f32 edgeAmpM` · `f32 edgeFreqIslands` · `i32 edgeSeedOffset` · `f32 edgeMaxShiftM` | Optional — present iff the terrain detail passes shaped this blueprint's `HGTS` (config `TerrainDetail: "v1"`, requires the curve). **`detailVersion` selects the body layout and a reader that does not recognise it SKIPS the section** (leaving detail metadata null) rather than misreading a differently shaped payload — the one section whose body is versioned rather than extended, because v1's layout was retired rather than grown. **v1 (retired, never shipped)** — shelf micro-relief + D8 drainage incision, 38 B; the incision produced grid-aligned artifacts and was reverted whole, so the only v1 payloads that exist are in that batch's own tree. **v2 (current)** — shelf micro-relief (±`reliefAmpM` output metres, shelf-ness weighted) + shelf-edge variation: a per-column shift of the curve's shelf/riser knot block K3/K4/K5, drawn from a Simplex field seeded `resolvedWorldSeed + edgeSeedOffset` at `edgeFreqIslands/MapSize`, amplitude ±`edgeAmpM` **metres of INPUT height** — a displacement of the shelf boundary contour, not an elevation change. `edgeAmpM` is recorded **as applied**, after the clamp to `edgeMaxShiftM` (the preset's band-squeeze bound), so the record always describes the terrain rather than the request. **Metadata only** — heights are already detailed. Machinery: `Tools/Scripts/TerrainDetailPass.cs`. | | `EROS` / `0x534F5245` | 67 B: `u16 erosionVersion` · `i32 dropletCount` · `i32 lifetime` · `i32 brushRadius` · `i32 seedOffset` · `f32 carveCapM` · `f32 depositCapM` · `f32 seaMarginM` · `f32 inertia` · `f32 capacityFactor` · `f32 minSlopeM` · `f32 erodeRate` · `f32 depositRate` · `f32 evaporation` · `f32 gravity` · `f32 craterCoreFactor` · `f32 craterFeatherFactor` · `u8 craterMode` | Optional — present iff the droplet hydraulic-erosion pass shaped this blueprint's `HGTS` (config `Erosion: "v1"`, terrain-water tasks 17–19). **`erosionVersion` selects the body layout; an unrecognised version is SKIPPED whole** (erosion metadata left null), same rule as `TDTL`. **v1 (task 17)** — 58 B, no `depositCapM`; deposition was bilinear over 4 cells and unbounded, which built isolated cones (measured 15.5 m). **v2 (task 18)** — 62 B; deposition brush-spread and per-cell bounded. **v3 (task 19, current)** — replaces v2's single `craterExclFactor` with `craterCoreFactor` (the protected strike core), `craterFeatherFactor` and `craterMode` (`0` = full, `1` = feather). Only v2+ payloads exist outside tasks 17–18's own batch trees. The FOUR governors are `dropletCount`/`lifetime`/`carveCapM`/`depositCapM`; both caps are enforced against one per-cell NET displacement ledger (positive = carved below the height the pass found, negative = built up above it) and asserted on exit. `seaMarginM` is the flood-guard clamp — no cell is carved below sea + margin, and below-sea cells are untouched in BOTH directions, so the rendered coastline cannot move **and the crater's flooded bay can be neither carved open nor silted shut regardless of `craterMode`**. Crater radii are FACTORS of `PRMS.CraterRadius`: nothing inside `craterCoreFactor ×` it is modified; `feather` ramps erosion 0→full from there out to `craterFeatherFactor ×` it, `full` applies full strength immediately. Droplets are deterministic from `resolvedWorldSeed + seedOffset` (PCG32). Remaining fields are the droplet-model strength dials; slopes/amounts in metres (1 raw = 251 m). All values recorded **as applied** (post config clamping). **Metadata only** — heights are already eroded, and the classify-side sections (`BIOM`/`WBID`/…) never saw the pass by design. Machinery: `Tools/Scripts/HydraulicErosion.cs`. | | `WBID` / `0x44494257` | `MapSize²` × `u16` water-body id, same pixel order as `HGTS` | Optional (absent = no water data, e.g. a legacy re-encode). `0` = no water, `1` = **the** ocean body, `2..N` = lakes. Ids assigned in deterministic scan order (X outer / Y inner, first-encountered pixel), lakes labeled with the **same 4-connectivity as `CalculateTrueOcean`**. Membership is exactly the generator's water classification — the biome grid's Ocean/Lake pixels and this grid's nonzero pixels are the same set **by construction** (shared predicates). Length must equal `2·MapSize²`. | -| `WBTB` / `0x42544257` | `i32 count`, then per body (20 B): `u16 id` · `u8 type` (0 ocean, 1 lake) · `u8 salinity` (0 fresh, 1 salt) · `f32 surfaceLevel` · `i32 pixelCount` · `f32 centroidX` · `f32 centroidY` | Optional, paired with `WBID`. **`surfaceLevel` is a documented TRANSITIONAL rule:** one flat level per body — `GetSeaLevel` at the body's pixel centroid (ocean: at the map centre) under the still-live latitude field; superseded by the flat-scalar sea model (minted, lands with the coast change set). The field's per-pixel slope is deliberately NOT baked into any section. **Salinity is a provisional default** (ocean salt, lake fresh) — a placeholder for the future fresh/salt irrigation mechanic, not a mechanic. | +| `WBTB` / `0x42544257` | `i32 count`, then per body (20 B): `u16 id` · `u8 type` (0 ocean, 1 lake, 2 river — a stepped river REACH, one flat level per reach; task 23) · `u8 salinity` (0 fresh, 1 salt) · `f32 surfaceLevel` · `i32 pixelCount` · `f32 centroidX` · `f32 centroidY` | Optional, paired with `WBID`. **`surfaceLevel` is a documented TRANSITIONAL rule:** one flat level per body — `GetSeaLevel` at the body's pixel centroid (ocean: at the map centre) under the still-live latitude field; superseded by the flat-scalar sea model (minted, lands with the coast change set). The field's per-pixel slope is deliberately NOT baked into any section. **Salinity is a provisional default** (ocean salt, lake fresh) — a placeholder for the future fresh/salt irrigation mechanic, not a mechanic. | | `WSRF` / `0x46525357` | `MapSize²` × `u16` quantized water-surface elevation, same pixel order | Optional, paired with `WBID`. `0` is the reserved **no-water sentinel**; a real level `L` (raw height units) encodes as `1 + round(L × 32768)` so it can never encode to 0; decode `(q − 1)/32768` (`BlueprintFormat.EncodeWaterLevel`/`DecodeWaterLevel`). Covers `[0 … ~1.99997]` raw at `1/32768` raw ≈ **7.7 mm** of world height (1 raw = 251 m) — far finer than the 1 m voxel. Nonzero exactly where `WBID` is nonzero; the value is the pixel's body level. | | `RDHW` / `0x57484452` | `i32 pathCount`, then per path: `i32 pointCount` + `pointCount` × (`f32 X` · `f32 Y`) | Highway tier. **Tags, not file position, identify the tier** — the v1 order-fragility is gone. Road sections may legitimately be **present but empty** (zero paths): the `SkipRoads` config toggle exports a road-less iteration blueprint. | | `RDBR` / `0x52424452` | same layout | Branch tier. | diff --git a/Tools/Scripts/README.md b/Tools/Scripts/README.md index 53398ab..98e039a 100644 --- a/Tools/Scripts/README.md +++ b/Tools/Scripts/README.md @@ -109,7 +109,24 @@ Generates the entire 2D blueprint. Roughly in order: sea + `RiverSeaMargin` everywhere (the erosion flood-guard discipline: below-sea cells read-only, zero new below-sea cells, coastline provably fixed; asserted per generation). Slots AFTER towns (town placement reads the render map and must not shift) and BEFORE roads. - Crater core excluded. **NO WATER yet** — part 2b waters the gated routing style. + Crater core excluded. + + **River water (task 23, C0b finale)** — the payoff. Each carved main river becomes a chain of + **stepped flat water-body REACHES**: a new reach starts every `RiverStepDropM` (2 m) of bed + descent and sits `RiverWaterDepthM` (1.2 m) above its bed, each reach strictly lower than the + one upstream, stepping down to the sea (small vertical drops — riffles — smoothable purely by + the step dial; tilted continuous-slope water is the deferred model B). Reaches are ordinary + water bodies: WBID cells + a WBTB entry (`type 2 = river`, fresh) each; WSRF derives from body + levels exactly as for lakes, and river water renders through the C1/task-13 path with the + task-15 presence rule at its banks. Lake-enders route the last reach into their lake by the + lowground Dijkstra (a pooling terminal IS a local minimum — blind descent dead-ends there); + rivers meet lakes and the sea without repainting them (existing bodies are never overwritten). + Only the lowland reaches are ROUTE-SMOOTHED (RDP+Chaikin, the road pipeline): the upland stems + already thread carved valley floors, and smoothing them off-line cut valley walls (measured). + The BIOME oracle holds (classify untouched; `1_biomes` md5-identical); `0_water` and the + re-captured `0_height` change — that IS the river water and its beds (both snapshots are + re-captured after the river pass so the exported PNGs show them). Max-cut is now reported + CUMULATIVELY vs the pre-pass surface. 3. **Sea level and water** — sea level per the configured model (`SeaLevelModel`: `"flat"` scalar — the default, `SeaLevelValue` 0.15 — or the legacy `"field"` latitude Lerp); flood fill diff --git a/Tools/Scripts/RiverCarvePass.cs.uid b/Tools/Scripts/RiverCarvePass.cs.uid new file mode 100644 index 0000000..728bfbb --- /dev/null +++ b/Tools/Scripts/RiverCarvePass.cs.uid @@ -0,0 +1 @@ +uid://dufsppmyn4g8v