All three gate polish items — they interleave in the same files, so they land as one buildable commit rather than three that do not compile independently. 1. TRIBUTARY WATER. Tributaries carved in task 22/23 but stayed dry: they were never registered with the water stage. They now are (as CarvedRiver entries named 'trib', kept OUT of the per-river console table so it stays the 6 mains). RiverTribWaterMinFlow (40k px of along-course flow) sets where water starts; RiverTribTaperPx (120 px) makes the wet->dry transition a FADE, not a wall — across the taper the wet strip narrows (0.25x -> 1x half-width) AND its surface drops toward the bed, so a stream head thins out and vanishes. Along-course flow is modelled quadratically from headwater trickle to full drainage at the mouth (the plan records drainage per river, not per sample). RiverTribWaterMinFlow=0 waters them end to end — the documented fallback. 2. LAKE-ENDER TARGETING. The join routed to the nearest classify-water CELL, which a 322-px puddle satisfies; it stopped ~80 px short of the 197k-px lagoon beside it. It now routes to a SIGNIFICANT water mask (bodies of at least RiverLakeMinTargetPx = 20k cells, built from the water-body table), falling back to any classify water only if no significant body is reachable, so a seed with genuinely small ponds still connects. Proven by adjacency: task 23 had 63 river cells touching the puddle and 0 touching the lagoon; task 24 has 49 touching the lagoon and 0 touching the puddle. 3. FINER STEPS + DEEPER BEDS. RiverStepDropM 2.0 -> 0.6 and RiverWaterDepthM 1.2 -> 2.2, RiverDepthScale 1.0 -> 1.5. Reaches 298 -> 1034; the level gap between adjacent reaches drops from median 0.571 m / p95 2.08 m to median 0.124 m / p95 0.74 m — the pond-staircase reads as a graded descent. Reaches stay trivial bodies (median 44 px). Guards all held: flood guard 0 newly-below-sea and 0 below-sea cells modified, BIOME oracle md5-identical to the task-22 baseline (output-only unchanged), island top 457.65 m exact, crater core excluded, lowest carved cell exactly sea+margin (37.85 m). Cumulative max cut 25.98 m with 339 cells >20 m — identical to task 23, so deepening the WATER did not deepen the worst cuts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| BiomePalette.cs | ||
| BiomePalette.cs.uid | ||
| BlockData.cs | ||
| BlockData.cs.uid | ||
| BlockRegistry.cs | ||
| BlockRegistry.cs.uid | ||
| BLUEPRINT_FORMAT.md | ||
| BlueprintFormat.cs | ||
| BlueprintFormat.cs.uid | ||
| BlueprintWriter.cs | ||
| BlueprintWriter.cs.uid | ||
| ChunkData.cs | ||
| ChunkData.cs.uid | ||
| ConfigManager.cs | ||
| ConfigManager.cs.uid | ||
| Constants.cs | ||
| Constants.cs.uid | ||
| Enums.cs | ||
| Enums.cs.uid | ||
| MapDataParser.cs | ||
| MapDataParser.cs.uid | ||
| MarchingCubes.cs | ||
| MarchingCubes.cs.uid | ||
| MATH_MARCHING_CUBES.md | ||
| README.md | ||
/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 (AIR0,BEDROCK,STONE,DIRT,SAND, the three grasses,SNOW,WASTELAND_DIRT,ASPHALT,WATER) with a safeGetBlocklookup. Block IDs are never serialized — the blueprint stores heights, biome ordinals and water data, never block IDs, and chunks are not persisted — so appending to this table is wire-safe.WATERis a registry identity only: it is not written intoChunkData.BlockIDs, because water is drawn as its own surface rather than as part of the terrain iso-surface (seeClient/README.md).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.cs—Biome,TownTier,MapHalf,RoadTier.⚠
BiomeandTownTierare the.datwire 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.RoadTieris exempt: road tiers live in separate sections of the file, so it is never serialized.
World data
BLUEPRINT_FORMAT.md— the byte-accurate.datcontainer 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 aWorldBlueprintas a v2 file. Blueprint-typed on purpose: the map generator and the round-trip harness are both just callers.MapDataParser.cs— decodes a.datblueprint into aWorldBlueprint(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,WaterBodiestable,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. The water sections are consumed at runtime since task 13 — the server reads them per column and the client draws the result (seeServer/README.md).ChunkData.cs— one chunk's density and block-ID fields,+1padded on every axis so the mesher can reach into the neighbouring chunk, plus the per-column data the renderer needs — includingWaterSurfaceY(world Y of the water surface, orConstants.NO_WATER),WaterDepthM(true depth from blueprint heights) andHasAnyWater.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), plus the water-at-rest tunables:HEIGHT_SCALE(the one raw-height→metres mapping, shared by the terrain surface and the water sheet so they cannot drift apart),NO_WATER, and the depth-shading colour/alpha ramp.
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
- No Godot node inheritance. Pure classes, structs and statics.
- No
_Process/_Ready. Nothing here is attached to a live scene object. - Dependencies flow inward only.
/Serverand/Clientreference/Core;/Corenever references them.