namespace IslaApocalypse.Tools
{
///
/// Everything pass 1 produces. → .
///
/// ⭐ THREE OF THESE FIELDS ARE THE PHASE-2 SEAM. The reference computed them in pass 1 and
/// consumed them in pass 2; exposing them now is what keeps the deferred ports clean, and it
/// costs nothing to carry.
///
public sealed class Pass1Result
{
/// Map side in columns.
public readonly int MapSize;
/// The resolved seed this was generated with. Always positive, always recorded.
public readonly int Seed;
///
/// The raw pass-1 height field, [x, y]. Pre-curve, pre-erosion, pre-crater.
/// The reference's finalH (~:619) written to _heightMap (~:666).
///
public readonly float[,] Height;
///
/// ⭐ PHASE-2 SEAM — the falloff value captured BEFORE the Pow(·, 2.5f) and BEFORE the
/// Trench wall (reference ~:591, preTrenchFalloff).
///
/// It is the "how far past the island body are we" number, uncontaminated by the power's
/// curvature and by the Trench's additive ramp. The DEFERRED offshore-islet layer reads it
/// as its distance mask (OffshoreZoneWeight), which is the only reason it is captured
/// mid-computation rather than recomputed.
///
/// ⚠ A port that "tidies" the falloff chain into one expression destroys this capture point,
/// and the loss would not show up until Phase 2's offshore mask moved. It is exposed here so
/// that cannot happen quietly.
///
public readonly float[,] PreTrenchFalloff;
///
/// ⭐ PHASE-2 SEAM — the wobbled latitude scalar, [x, y].
///
/// ⚠ THIS IS NOT A CLIMATE TEMPERATURE MAP. See for the full note.
/// It is a stage-1-local latitude field that terrain GEOMETRY reads. Phase 2 needs it if the
/// latitude sea-level model is ever switched on (SeaLevelModel = "field"); under the
/// shipped flat model it has no consumer beyond the spine.
///
public readonly float[,] LatitudeField;
///
/// ⭐ PHASE-2 SEAM — the maximum height over the whole map (reference _hMaxSeed, ~:665).
///
/// The reference's v2+ redistribution curve is SEED-DEPENDENT: its spike maps
/// [t4, hMaxSeed] onto the peak band, so pass 2 cannot start until pass 1 has scanned
/// every pixel. That is precisely why the pass-1/pass-2 boundary is a hard one and not an
/// interleave. Carried here so Phase 2 inherits it rather than rediscovering the dependency.
///
public readonly float HMaxSeed;
/// The minimum height. Not a reference field — carried for the renderer's ramp and the report.
public readonly float HMinSeed;
/// Wall-clock milliseconds the pass took.
public readonly ulong ElapsedMs;
public Pass1Result(int mapSize, int seed, float[,] height, float[,] preTrenchFalloff,
float[,] latitudeField, float hMaxSeed, float hMinSeed, ulong elapsedMs)
{
MapSize = mapSize;
Seed = seed;
Height = height;
PreTrenchFalloff = preTrenchFalloff;
LatitudeField = latitudeField;
HMaxSeed = hMaxSeed;
HMinSeed = hMinSeed;
ElapsedMs = elapsedMs;
}
/// Fraction of the map at or above the sea threshold. A cheap shape sanity number.
public float LandFraction(float seaLevel)
{
long land = 0;
for (int x = 0; x < MapSize; x++)
for (int y = 0; y < MapSize; y++)
if (Height[x, y] >= seaLevel) land++;
return land / (float)((long)MapSize * MapSize);
}
}
}