revert: the D8 drainage incision, whole (terrain-water task 10)
The task-10 draft's PASS B shipped and produced the canonical grid
artifact: thousands of straight, disconnected, pooling scratches. Per-
cell steepest descent on a regular grid can only route along its eight
neighbour headings, so at map scale the "channels" read as hatching,
not drainage. Reverted entirely rather than tuned -- no K, p or mask
setting fixes a directional basis. Rivers and erosion move to Phase C
as a hydraulic-erosion pass over FINAL terrain.
Removed: FlowAccumulation / IncisionWeight / EdgeBlend and the INC_*,
SEA_CLAMP, SHELF_INC_WEIGHT and CRATER_* constants; RunIncisionPass and
the pass-2b call; the six incision fields from TDTL (writer, parser,
harness). KEPT, untouched and developer-approved: pass A, the shelf
micro-relief skin, and its ShelfReliefAmp dial.
The crater carve folds back into the single pass-2 loop it came from,
carving two LOCALS written once each. That is what the code did before
the draft split it out, and it makes the aliased double-carve that the
split introduced (fix 1b98fb5) structurally impossible rather than
merely fixed -- there is no longer a read-modify-write to get wrong.
TDTL bodies are now versioned (BlueprintFormat.TDTL_VERSION = 2) and the
parser skips a body version it does not know instead of misreading the
longer v1 layout into plausible nonsense. The only v1 payloads that
exist are in the reverted batch's own tree.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e3f7b508e7
commit
3b6d166458
7 changed files with 56 additions and 224 deletions
|
|
@ -35,6 +35,13 @@ namespace IslaApocalypse.Core
|
|||
public const uint TAG_TERRAIN_CURVE = 0x56524354; // "TCRV"
|
||||
public const uint TAG_TERRAIN_DETAIL = 0x4C544454; // "TDTL"
|
||||
|
||||
// TDTL body version. 1 = shelf micro-relief + D8 drainage incision (the
|
||||
// task-10 draft; the incision was reverted, and the only v1 payloads in
|
||||
// existence are in that batch's tree). 2 = the current body. A reader that
|
||||
// meets an unrecognised body version skips it rather than misreading a
|
||||
// differently shaped payload into plausible-looking nonsense.
|
||||
public const ushort TDTL_VERSION = 2;
|
||||
|
||||
// WSRF quantization: u16, 0 reserved as the no-water sentinel. A real level L
|
||||
// (raw blueprint height units) encodes as 1 + round(L × 32768), so a genuine
|
||||
// level can never encode to 0. Decodes back via (q − 1) / 32768. Covers
|
||||
|
|
|
|||
|
|
@ -155,12 +155,9 @@ namespace IslaApocalypse.Core
|
|||
|
||||
private static void WriteTerrainDetail(BinaryWriter writer, TerrainDetailInfo d)
|
||||
{
|
||||
writer.Write(d.Version);
|
||||
writer.Write(d.ReliefAmpM); writer.Write(d.ReliefFreqIslands);
|
||||
writer.Write(d.IncK); writer.Write(d.IncP); writer.Write(d.IncCapM);
|
||||
writer.Write(d.SeaClampRaw); writer.Write(d.CraterExclFactor);
|
||||
writer.Write(d.ShelfIncWeight);
|
||||
writer.Write(d.ReliefSeedOffset);
|
||||
writer.Write(d.Version); // u16
|
||||
writer.Write(d.ReliefAmpM); writer.Write(d.ReliefFreqIslands); // 2 × f32
|
||||
writer.Write(d.ReliefSeedOffset); // i32
|
||||
}
|
||||
|
||||
private static void WriteWaterBodyIds(BinaryWriter writer, WorldBlueprint bp)
|
||||
|
|
|
|||
|
|
@ -33,10 +33,9 @@ namespace IslaApocalypse.Core // Change this if your namespace is different
|
|||
// are retired. Default: v5.
|
||||
public static string TerrainCurve = "v5";
|
||||
|
||||
// Terrain detail passes (task 10): "v1" = shelf micro-relief + drainage
|
||||
// incision as one judged unit (requires the curve; no-op when it is off);
|
||||
// "off" disables both. ShelfReliefAmp is the micro-relief amplitude in
|
||||
// metres. Defaults: v1, 3 m.
|
||||
// Terrain detail passes (task 10): "v1" = shelf micro-relief (requires the
|
||||
// curve; no-op when it is off), "off" disables it. ShelfReliefAmp is the
|
||||
// micro-relief amplitude in metres. Defaults: v1, 3 m.
|
||||
public static string TerrainDetail = "v1";
|
||||
public static float ShelfReliefAmp = 3.0f;
|
||||
|
||||
|
|
|
|||
|
|
@ -89,15 +89,15 @@ namespace IslaApocalypse.Core
|
|||
|
||||
/// <summary>
|
||||
/// The terrain detail passes that shaped this blueprint's HGTS (v2 TDTL section,
|
||||
/// terrain-water task 10): shelf micro-relief + drainage incision parameters.
|
||||
/// Null when detail was off. Metadata only — heights are already detailed.
|
||||
/// terrain-water task 10): the shelf micro-relief parameters. Null when detail
|
||||
/// was off. Metadata only — heights are already detailed. Body version 1 (the
|
||||
/// reverted relief + D8-incision layout) is longer and differently shaped; the
|
||||
/// parser refuses it rather than misreading it.
|
||||
/// </summary>
|
||||
public class TerrainDetailInfo
|
||||
{
|
||||
public ushort Version;
|
||||
public float ReliefAmpM, ReliefFreqIslands;
|
||||
public float IncK, IncP, IncCapM;
|
||||
public float SeaClampRaw, CraterExclFactor, ShelfIncWeight;
|
||||
public int ReliefSeedOffset;
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ namespace IslaApocalypse.Core
|
|||
else if (tag == BlueprintFormat.TAG_WATER_SURFACE) sectionOk = ParseWaterGrid(reader, blueprint, payloadLength, isSurface: true);
|
||||
else if (tag == BlueprintFormat.TAG_WATER_BODY_TABLE) sectionOk = ParseWaterBodyTable(reader, blueprint);
|
||||
else if (tag == BlueprintFormat.TAG_TERRAIN_CURVE) sectionOk = ParseTerrainCurve(reader, blueprint);
|
||||
else if (tag == BlueprintFormat.TAG_TERRAIN_DETAIL) sectionOk = ParseTerrainDetail(reader, blueprint);
|
||||
else if (tag == BlueprintFormat.TAG_TERRAIN_DETAIL) sectionOk = ParseTerrainDetail(reader, blueprint, payloadLength);
|
||||
else
|
||||
{
|
||||
// The property the redesign exists to buy: future sections (water,
|
||||
|
|
@ -448,14 +448,19 @@ namespace IslaApocalypse.Core
|
|||
return true;
|
||||
}
|
||||
|
||||
private static bool ParseTerrainDetail(BinaryReader reader, WorldBlueprint blueprint)
|
||||
private static bool ParseTerrainDetail(BinaryReader reader, WorldBlueprint blueprint, ulong payloadLength)
|
||||
{
|
||||
var d = new TerrainDetailInfo();
|
||||
d.Version = reader.ReadUInt16();
|
||||
if (d.Version != BlueprintFormat.TDTL_VERSION)
|
||||
{
|
||||
// Skip the body and leave TerrainDetail null. The heights are still
|
||||
// whatever they are — we simply refuse to describe them wrongly.
|
||||
GD.PrintErr($"[MapDataParser] ⚠ TDTL body version {d.Version} is not the current {BlueprintFormat.TDTL_VERSION} — section skipped, detail metadata unavailable.");
|
||||
reader.BaseStream.Seek((long)payloadLength - 2L, SeekOrigin.Current);
|
||||
return true;
|
||||
}
|
||||
d.ReliefAmpM = reader.ReadSingle(); d.ReliefFreqIslands = reader.ReadSingle();
|
||||
d.IncK = reader.ReadSingle(); d.IncP = reader.ReadSingle(); d.IncCapM = reader.ReadSingle();
|
||||
d.SeaClampRaw = reader.ReadSingle(); d.CraterExclFactor = reader.ReadSingle();
|
||||
d.ShelfIncWeight = reader.ReadSingle();
|
||||
d.ReliefSeedOffset = reader.ReadInt32();
|
||||
blueprint.TerrainDetail = d;
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue