islaApocalypse/Core/Scripts
beezm 9c255a4fc6 feat: render the water we already had (terrain-water task 13, Phase C1)
The blueprint has carried water since task 03 -- WBID per-pixel body id,
WBTB body table, WSRF per-pixel surface level. Nothing ever drew it. Now
the runtime does. No new water data: the blueprint is the authority on
where water is and at what level, and this only reads it.

WHY WATER IS ITS OWN MESH, not a block in the terrain field. The terrain
is a Marching-Cubes iso-surface over ChunkData.Densities. Writing WATER
into that field would not lay a sheet on top of the seabed -- it would
move the iso-surface, fusing the sea into the terrain as if it were solid
ground. A second surface is the only way water can sit at ITS level
independent of the ground under it. So ChunkRenderer builds a water
MeshInstance3D as a child of the chunk's terrain mesh.

TRANSPARENCY IS SHIPPED, NOT DEFERRED (Step 2.4's cheap branch). Because
water is a distinct MeshInstance3D it carries its own StandardMaterial3D,
so alpha is one flag and Godot sorts transparent surfaces after opaque
ones by itself. Zero mesher changes. Alpha runs 0.62 shallow -> 0.97 deep,
so the shelved coast stays readable and open ocean closes up.

WHICH DATA DROVE IT: WSRF for the level (per-pixel, quantised to 1/32768
raw ~ 7.7 mm, far under the 1 m voxel, and no table lookup), WBID for
presence (it is the water stage's own classification output -- the same
set the biome grid's Ocean/Lake pixels form by construction), WBTB as the
fallback when a column is flagged wet but carries the WSRF no-water
sentinel. A body the table does not know leaves the column DRY rather
than guessing a level.

Details worth keeping:
- Water Y uses Constants.HEIGHT_SCALE, the SAME mapping as the terrain
  surface, named so the sheet and the seabed cannot drift apart if the
  vertical band is ever retuned.
- Depth for shading comes from BLUEPRINT heights, not rendered geometry:
  the terrain render clamps its floor at Y=2, so every deep-ocean column
  would otherwise read as one flat ~36 m and the gradient would die
  exactly where the ocean gets interesting.
- A cell is drawn if ANY corner is wet, flat at the highest wet level.
  Drawing onto a partly-dry cell is deliberate -- it carries the sheet
  under the shoreline where the opaque terrain hides it. Only-fully-wet
  cells retreat the waterline a metre and leave a dry gap around every
  coast and lake.
- Non-metallic, roughness 0.35: the scene environment is minimal, and a
  metallic surface reads near-black when there is nothing to reflect.

BlockRegistry gains WATER (id 11). Wire-safe: block IDs are never
serialized -- the blueprint's section table stores heights, biome ordinals
and water data, never block IDs, and chunks are not persisted yet.

MEASURED on seed 1825907253: 241,415 water columns across 454 of 4096
chunks; surface Y 37.6..37.6 m (flat, = 0.15 x 251 -- the flat sea model,
rendered); depth to 32.3 m, matching an independent read of the blueprint
exactly. Both an ocean and a lake fall in the default view.

NO REGRESSION to the 2D pipeline, verified section by section: a
regeneration of the working seed is byte-identical to task 12's run in
TCRV, TDTL, HGTS, BIOM, WBID, WBTB, WSRF, TOWN and all four road
sections; only PRMS differs, and only in its write timestamp. All four
snapshot PNGs md5-identical.

No storms, no waves, no animation, no flow -- water at rest. Those are C2+.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 02:32:04 -04:00
..
BiomePalette.cs roads: enable Rugged+Trail carving + per-tier character (D-022) 2026-08-05 03:53:32 -04:00
BiomePalette.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
BlockData.cs baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
BlockData.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
BlockRegistry.cs feat: render the water we already had (terrain-water task 13, Phase C1) 2026-08-09 02:32:04 -04:00
BlockRegistry.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
BLUEPRINT_FORMAT.md docs: island falloff, coast shelf, offshore islets (terrain-water task 11) 2026-08-08 23:31:40 -04:00
BlueprintFormat.cs revert: the D8 drainage incision, whole (terrain-water task 10) 2026-08-08 20:30:44 -04:00
BlueprintFormat.cs.uid chore: Godot .uid files for the new task-02 scripts 2026-08-07 00:17:46 -04:00
BlueprintWriter.cs feat: shelf-edge variation -- the red-line scalloping (terrain-water task 10) 2026-08-08 20:31:41 -04:00
BlueprintWriter.cs.uid chore: Godot .uid files for the new task-02 scripts 2026-08-07 00:17:46 -04:00
ChunkData.cs feat: render the water we already had (terrain-water task 13, Phase C1) 2026-08-09 02:32:04 -04:00
ChunkData.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
ConfigManager.cs fix: IslandAxis defaults to the gate's verdict, 1.15/0.90 (terrain-water task 13) 2026-08-09 02:20:35 -04:00
ConfigManager.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
Constants.cs feat: render the water we already had (terrain-water task 13, Phase C1) 2026-08-09 02:32:04 -04:00
Constants.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
Enums.cs roads: enable Rugged+Trail carving + per-tier character (D-022) 2026-08-05 03:53:32 -04:00
Enums.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
MapDataParser.cs feat: shelf-edge variation -- the red-line scalloping (terrain-water task 10) 2026-08-08 20:31:41 -04:00
MapDataParser.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
MarchingCubes.cs roads: enable Rugged+Trail carving + per-tier character (D-022) 2026-08-05 03:53:32 -04:00
MarchingCubes.cs.uid baseline: working salvaged prototype on Godot 4.7.1 (pre-F1) 2026-08-05 01:45:41 -04:00
MATH_MARCHING_CUBES.md docs: fix MATH_MARCHING_CUBES §4 polarity + dims 2026-08-05 21:32:51 -04:00
README.md docs: water sections (WBID/WBTB/WSRF), no-BSIN rationale, SkipRoads + water stage in READMEs (terrain-water task 03) 2026-08-07 01:40:48 -04:00

/Core/Scripts

Pure C# data structures, shared enums, and static maths. Compiled into the shared assembly used by both /Server and /Client.

"Pure data, zero state." These scripts define what things are and how to calculate them. They never track live game events — who is online, which chunks are loaded, what time it is.

What's actually here

Voxel materials

  • BlockData.cs — struct describing one block type (ID, name, IsSolid, BaseColor).
  • BlockRegistry.cs — the byte-ID master list (AIR 0, BEDROCK, STONE, DIRT, SAND, the three grasses, SNOW, WASTELAND_DIRT, ASPHALT) with a safe GetBlock lookup.
  • BiomePalette.cs — decides which material sits where, given biome, depth, and whether the column is roadbed. Two paths on purpose: an integer classification that decides what is stored in each voxel, and a float-depth version used for rendering that returns the two materials either side of a boundary so colours fade rather than snap.

⚠ Note that BlockRegistry and the mesher's colour table hold different RGB values for some blocks. The mesher's table is what you actually see; BlockData.BaseColor is currently unused by rendering.

Shared identifiers

  • Enums.csBiome, TownTier, MapHalf, RoadTier.

    Biome and TownTier are the .dat wire format (u8 in the v2 container, i32 in legacy v1). They are declared without explicit values, so each member's ordinal is the number written to disk. Append only, at the end — never reorder or insert. The v2 reader range-checks ordinals so drift fails loudly at parse time, but only the append-only rule keeps old files meaning the same thing. Legacy v1 has no gate and no validation at all. RoadTier is exempt: road tiers live in separate sections of the file, so it is never serialized.

World data

  • BLUEPRINT_FORMAT.md — the byte-accurate .dat container contract (v2 tagged sections + the v1 legacy summary). Read this before touching the writer or parser.
  • BlueprintFormat.cs — the single registry of v2 constants: magic, version gate, section tags (FourCC), validation bounds, re-encode sentinels.
  • 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, 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. 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 (material blend band; per-tier road width, shoulder, grade smoothing and surface).

Maths

  • MarchingCubes.cs — density field → ArrayMesh, with analytical normals and deterministic integer-keyed vertex welding.
  • MATH_MARCHING_CUBES.md — an explainer of the algorithm.

Rules

  1. No Godot node inheritance. Pure classes, structs and statics.
  2. No _Process / _Ready. Nothing here is attached to a live scene object.
  3. Dependencies flow inward only. /Server and /Client reference /Core; /Core never references them.