feat: droplet hydraulic erosion — carve+deposit, three governors, sea clamp (terrain-water task 17, Phase C0)
Erosion: "off"|"v1" gate (default off, pending the developer's gate). Output-only: applied to the render map after detail, before the crater carve; the classify path reads pre-erosion heights, so biomes/water stay byte-identical (verified: OFF run bit-identical to the task-14 reference; ON run BIOM/WBID identical to OFF). Governors: droplet count / lifetime / per-cell carve cap (ledger-enforced, thrown on violation). Sea clamp: below-sea cells read-only, land never carved below sea+margin — rendered coastline provably fixed (asserted per generation). Crater excluded at 1.2×R. Deterministic from resolvedSeed+9271 (PCG32). New EROS blueprint section (writer/parser/harness/format doc). Supersedes the reverted D8 approach with the organic droplet model. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
34b0e1c9e3
commit
e1e1fe3227
8 changed files with 611 additions and 22 deletions
|
|
@ -122,6 +122,7 @@ public partial class RoundTripHarness : Node
|
|||
ok &= CompareWater(a, b);
|
||||
ok &= CompareTerrainCurve(a, b);
|
||||
ok &= CompareTerrainDetail(a, b);
|
||||
ok &= CompareErosion(a, b);
|
||||
|
||||
if (ok)
|
||||
GD.Print($"[Harness] Semantic equality holds: {a.MapSize}x{a.MapSize} grid, " +
|
||||
|
|
@ -241,6 +242,33 @@ public partial class RoundTripHarness : Node
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool CompareErosion(WorldBlueprint a, WorldBlueprint b)
|
||||
{
|
||||
if (a.Erosion == null && b.Erosion == null)
|
||||
{
|
||||
GD.Print("[Harness] EROS: absent in source — nothing to compare (and none reappeared).");
|
||||
return true;
|
||||
}
|
||||
if (a.Erosion == null || b.Erosion == null)
|
||||
{
|
||||
GD.PrintErr("[Harness] EROS presence mismatch between source and reread.");
|
||||
return false;
|
||||
}
|
||||
var ea = a.Erosion; var eb = b.Erosion;
|
||||
bool same = ea.Version == eb.Version
|
||||
&& ea.DropletCount == eb.DropletCount && ea.Lifetime == eb.Lifetime
|
||||
&& ea.BrushRadius == eb.BrushRadius && ea.SeedOffset == eb.SeedOffset;
|
||||
float[] fa = { ea.CarveCapM, ea.SeaMarginM, ea.Inertia, ea.CapacityFactor, ea.MinSlopeM,
|
||||
ea.ErodeRate, ea.DepositRate, ea.Evaporation, ea.Gravity, ea.CraterExclFactor };
|
||||
float[] fb = { eb.CarveCapM, eb.SeaMarginM, eb.Inertia, eb.CapacityFactor, eb.MinSlopeM,
|
||||
eb.ErodeRate, eb.DepositRate, eb.Evaporation, eb.Gravity, eb.CraterExclFactor };
|
||||
for (int i = 0; i < fa.Length; i++)
|
||||
if (System.BitConverter.SingleToInt32Bits(fa[i]) != System.BitConverter.SingleToInt32Bits(fb[i])) same = false;
|
||||
if (!same) { GD.PrintErr("[Harness] EROS fields differ."); return false; }
|
||||
GD.Print($"[Harness] EROS equal (erosion v{ea.Version}).");
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CompareRoads(string tier, List<Vector2[]> a, List<Vector2[]> b)
|
||||
{
|
||||
if (a.Count != b.Count)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue