diff --git a/Core/README.md b/Core/README.md index 8e5f52d..7654e74 100644 --- a/Core/README.md +++ b/Core/README.md @@ -17,7 +17,9 @@ dispatches on the file's first byte: - **v2 (primary)** — raw `ISLA` magic, u32 version gate, then tagged sections `[u32 tag][u64 length][payload]`. Unknown tags are skipped by length, so future sections are invisible to older readers. Validated on read: version, MapSize bounds, section lengths against - the file, biome/tier ordinal ranges. + the file, biome/tier ordinal ranges. Since the water-bodies stage, v2 files also carry the + optional `WBID`/`WBTB`/`WSRF` water sections (per-pixel body ids, the body table, quantized + surface levels) — parsed into `WorldBlueprint` and consumed by nothing at runtime yet. - **v1 (legacy)** — the positional `"ISLA_V1"` format, still written beside v2 as `_v1.dat` and still loadable (with a deprecation warning) until a future removal task. diff --git a/Core/Scripts/BLUEPRINT_FORMAT.md b/Core/Scripts/BLUEPRINT_FORMAT.md index b857c3f..493758f 100644 --- a/Core/Scripts/BLUEPRINT_FORMAT.md +++ b/Core/Scripts/BLUEPRINT_FORMAT.md @@ -55,7 +55,10 @@ Every section: `[u32 tag][u64 payload-length in bytes][payload]`. | `HGTS` / `0x53544748` | `MapSize²` × `f32` height, **X outer / Y inner** | Mandatory. The second index is the map's north/south axis; the server consumes it as world **Z**. (This axis convention was never written down for v1 — it is now normative.) Length must equal `4·MapSize²`. | | `BIOM` / `0x4D4F4942` | `MapSize²` × `u8` biome ordinal, same pixel order | Mandatory. Ordinals from `Enums.cs::Biome` — **append-only, never reorder** (the ordinal IS the wire value). Writer refuses ordinals > 255; reader rejects ordinals ≥ the known biome count (parse-time validation; the palette's runtime Dirt fallback for in-memory values is unchanged). Length must equal `MapSize²`. | | `TOWN` / `0x4E574F54` | `i32 count`, then per town: `f32 X` · `f32 Y` · `u8 tier` · `u8 isHighwayNode` (0/1) | Tier ordinals from `Enums.cs::TownTier`, append-only, range-checked on read. The highway-node flag is what the generator's road topology was built from (v1 dropped it); carried and exposed on the parsed blueprint, consumed by nothing server-side yet. | -| `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. | +| `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. | +| `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. | | `RDRG` / `0x47524452` | same layout | Rugged tier. | | `RDTL` / `0x4C544452` | same layout | Trail tier. | @@ -85,9 +88,20 @@ the file, not the original generation. ### Size -`total = 8 (header) + Σ per section (12 + payload)`. The pixel grid dominates: `5·MapSize²` bytes -(4 height + 1 biome) ≈ **320 MiB at 8K**, vs v1's `8·MapSize²` ≈ 512 MiB — the u8 biome section -saves ~192 MiB at 8K. +`total = 8 (header) + Σ per section (12 + payload)`. The pixel grids dominate: without water +sections `5·MapSize²` bytes (4 height + 1 biome) ≈ **320 MiB at 8K**, vs v1's `8·MapSize²` ≈ +512 MiB — the u8 biome section saves ~192 MiB. With the water sections the per-pixel cost is +`9·MapSize²` (adds 2 B `WBID` + 2 B `WSRF`) ≈ **576 MiB at 8K** plus a trivial `WBTB` (20 B per +body). + +### Deliberately NOT a section: basins (`BSIN`) + +The priority-flood pit-fill that runs in the water-bodies stage is **diagnostics only** and +serializes nothing. Rationale, on the record so nobody adds a basin section later without meeting +the argument: basin geometry is a pure function of the heightmap, and it goes stale the moment the +coast-smoothing change set (or any terrain change) touches heights — a serialized `BSIN` would be +a cache with a silent invalidation hazard. The rivers stage recomputes basins fresh at generation +time (measured ~12 s at 8K — cheap enough to never cache). ### Adding a new section (the intended extension path) diff --git a/Core/Scripts/README.md b/Core/Scripts/README.md index 31b56f8..d645894 100644 --- a/Core/Scripts/README.md +++ b/Core/Scripts/README.md @@ -39,10 +39,11 @@ rendering. - **`BlueprintWriter.cs`** — writes a `WorldBlueprint` as a v2 file. Blueprint-typed on purpose: the map generator and the round-trip harness are both just callers. - **`MapDataParser.cs`** — decodes a `.dat` blueprint into a `WorldBlueprint` (heightmap, biome map, - towns, four road tiers, and — v2 only — the embedded generation params and per-town highway-node - flag). Dispatches on the first byte: v2 tagged-section files get validation (version gate, size + towns, four road tiers, and — v2 only — the embedded generation params, per-town highway-node + flag, and the optional water-bodies data: `WaterBodyIds`, `WaterBodies` table, `WaterSurfaceQ`). + Dispatches on the first byte: v2 tagged-section files get validation (version gate, size bounds, section-length and ordinal range checks); legacy v1 files still load, intact, with a - deprecation warning. + deprecation warning. Nothing at runtime consumes the water data yet. - **`ChunkData.cs`** — one chunk's density and block-ID fields, `+1` padded on every axis so the mesher can reach into the neighbouring chunk, plus the per-column data the renderer needs. - **`Constants.cs`** — chunk dimensions, `ISO_LEVEL`, `VOXEL_SCALE`, and the visual/road tunables diff --git a/Tools/README.md b/Tools/README.md index 05fa653..0166168 100644 --- a/Tools/README.md +++ b/Tools/README.md @@ -17,6 +17,10 @@ Builds the topographical and logistical foundation of the island before any 3D e - **Topography:** FastNoiseLite plus distance-falloff maths for a guaranteed mainland island, a mountain spine, dynamic temperature-driven sea level, and an impact crater pushed into the northern coast (carved at 80 % of its radius so a landbridge always survives). +- **Water bodies:** the classified water promoted into explicit blueprint data (ocean + labeled + lakes with transitional per-body levels — `WBID`/`WBTB`/`WSRF` sections), plus priority-flood + basin diagnostics. The `SkipRoads` config toggle turns a full ~26-min generation into a ~80 s + road-less iteration cycle. - **Logistics:** `AStarGrid2D` pathfinding producing a looping continental highway, a branch to the mountain hub, and county roads daisy-chained outward with Prim's algorithm. Paths are decimated (Ramer–Douglas–Peucker) then smoothed (4 Chaikin passes). diff --git a/Tools/Scripts/README.md b/Tools/Scripts/README.md index deaf7c8..81d23d7 100644 --- a/Tools/Scripts/README.md +++ b/Tools/Scripts/README.md @@ -15,10 +15,18 @@ Generates the entire 2D blueprint. Roughly in order: inland lakes; a mainland fill guarantees one contiguous landmass. 4. **The crater** — placed along the northern coast and carved to below sea level, but only out to **80 % of its radius**, which guarantees a landbridge rather than severing the island. -5. **Biomes and towns** — biome zoning by height and temperature; tiered town placement (Capitol, +5. **Water bodies** — promotes the classified water into explicit data: the ocean as body 1, each + lake connected-component labeled (same 4-connectivity as the true-ocean fill), one transitional + surface level per body. Classification comes from the shared `IsOceanPixel`/`IsLakePixel` + predicates that the biome stage also uses, so the two can never disagree. A priority-flood + pit-fill runs here as validated diagnostics (basin statistics to console; serializes nothing). + Drops the `0_water` snapshot. +6. **Biomes and towns** — biome zoning by height and temperature; tiered town placement (Capitol, Hubs, Villages, Outposts, POIs) filtered by slope, water proximity and spacing. -6. **Roads** — see below. -7. **Export** — writes the `.dat` blueprint (dual-write: the v2 tagged container under the primary +7. **Roads** — see below. Skipped entirely when the `SkipRoads` config toggle is on (the ~25-min + A\* pass is the bottleneck; a skip run exports a road-less iteration blueprint in ~80 s with a + loud console banner). +8. **Export** — writes the `.dat` blueprint (dual-write: the v2 tagged container under the primary seed name, plus the legacy v1 format beside it as `_v1.dat` — see `Core/Scripts/BLUEPRINT_FORMAT.md`), then renders the PNG snapshot. The v2 file embeds the resolved generation params (seed, MapSize, crater radius, density, impact centre, provenance). @@ -55,8 +63,10 @@ Road colours on the snapshot, useful for identifying a road: **red** = Highway, **dark brown** = Rugged, **light brown** = Trail. ### Outputs -`MapData_Seed_.dat` (v2), `MapData_Seed__v1.dat` (legacy dual-write), and -`Map_Seed_.png`, all to `user://`. +`MapData_Seed_.dat` (v2), `MapData_Seed__v1.dat` (legacy dual-write), and the staged +snapshots `Map_Seed__{0_water,1_biomes,2_towns,3_roads}.png`, all to `user://`. (`0_water` +is painted from the water stage's own outputs — ocean deep blue, lakes lighter blue, land neutral; +`3_roads` is absent on a SkipRoads run.) ## `RoundTripHarness.cs`