islaApocalypse/Core/Scripts
beezm f810ff44dc fix: shrink erosion's crater exclusion to the strike core; add FULL/FEATHER modes (terrain-water task 19)
Task 17's hard 1.2 x CraterRadius cutoff left a visible un-eroded disc with a hard
edge. Measured (radius dump, seed 1280587109): the carve writes only inside 0.80 x
(640 px) and its displacement is EXACTLY 0 beyond that, so the 640-960 px annulus
was 620,811 LAND cells of ordinary terrain held smooth for no geometric reason.
That annulus is now eroded — 98% of those cells are touched.

The protected core is the carve's own extent (CraterErosionCore, 0.80 x).
CraterErosionMode selects the transition: "full" applies full strength at the core
boundary (older-crater look), "feather" ramps 0->full out to CraterErosionFeather
(1.05 x, mirroring the detail pass) for a younger-crater look with no seam.
Implemented as a WEIGHT that scales carve and deposit amounts, not a skip, which is
what makes feather a one-liner. Default "feather" pending the gate.

Core = the carve radius is load-bearing, not tidy: the carve runs AFTER erosion and
scales height toward the sea target, so it amplifies any erosion delta inside its
radius. Measured at a 0.50 core: 79 cells newly below the rendered sea and 113,310
below-sea cells disturbed — the in-pass flood guard cannot see this because it
measures before the carve. At 0.80 the two passes touch disjoint cells and the
guarantee is exact again (0/0/0). A narrower core also reclaims nothing extra, since
the over-protected annulus lies entirely outside the carve. MapGenerator now owns
CRATER_CARVE_FACTOR as the single source of that 0.80 and warns loudly if the
configured core is narrower.

Verified both modes, seed 1280587109: 1_biomes/0_water md5-identical to erosion-OFF,
BIOM/WBID bitwise equal, 0 newly below/above sea, 0 below-sea cells modified, 0
cells modified inside the core, island top 457.65 m unchanged, isotropy 1.005/1.007.
Bay-to-ocean connection demonstrated explicitly by flood fill through rendered
water to the map's north border (2,122,935 cells), not merely argued from the sea
clamp.

EROS body version -> 3: craterExclFactor replaced by craterCoreFactor +
craterFeatherFactor + craterMode. Round-trip harness PASS with a real v3 payload.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 05:50:22 -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: erosion hierarchy defaults, EROS v2, and where erosion cannot reach (terrain-water task 18) 2026-08-10 04:16:33 -04:00
BlueprintFormat.cs fix: shrink erosion's crater exclusion to the strike core; add FULL/FEATHER modes (terrain-water task 19) 2026-08-10 05:50:22 -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 fix: shrink erosion's crater exclusion to the strike core; add FULL/FEATHER modes (terrain-water task 19) 2026-08-10 05:50:22 -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: shrink erosion's crater exclusion to the strike core; add FULL/FEATHER modes (terrain-water task 19) 2026-08-10 05:50:22 -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 fix: shrink erosion's crater exclusion to the strike core; add FULL/FEATHER modes (terrain-water task 19) 2026-08-10 05:50:22 -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 at rest across the Core/Client/Server READMEs (terrain-water task 13) 2026-08-09 02:33:06 -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, WATER) with a safe GetBlock lookup. 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. WATER is a registry identity only: it is not written into ChunkData.BlockIDs, because water is drawn as its own surface rather than as part of the terrain iso-surface (see Client/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.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. The water sections are consumed at runtime since task 13 — the server reads them per column and the client draws the result (see Server/README.md).
  • 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 — including WaterSurfaceY (world Y of the water surface, or Constants.NO_WATER), WaterDepthM (true depth from blueprint heights) and HasAnyWater.
  • 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

  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.