namespace IslaApocalypse.Core
{
///
/// ⭐ THE WORLD'S VERTICAL YARDSTICK — the single metres↔raw-height conversion for the rewrite.
///
/// ═══ THE RULE ═══
///
/// THERE IS EXACTLY ONE METRES-PER-RAW-UNIT NUMBER, AND IT LIVES HERE.
/// No literal 251f anywhere. No second M_PER_UNIT. Ever.
///
/// ═══ ⚠⚠ WHY THIS TYPE EXISTS — THE PROTOTYPE'S SCATTER ═══
///
/// The reference had this number in ONE derived place and then wrote it out by hand everywhere:
///
/// • Core/Constants.cs: HEIGHT_SCALE = CHUNK_HEIGHT - 5 — the only DERIVED
/// definition, and the only one the runtime (ServerChunkManager) actually used.
/// • THREE independent hardcoded copies: HydraulicErosion.M_PER_UNIT = 251f,
/// DrainageAnalysis.M_PER_UNIT = 251f, RiverCarvePass.M_PER_UNIT = 251f.
/// • ~20 bare 251f literals across HeightCurve and MapGenerator.
///
/// So the GENERATOR never used the derived constant at all. Retuning the chunk height would have
/// moved the runtime's yardstick and left every generated constant behind — silently, because a
/// literal does not throw. (chat2/00 report § C.7.)
///
/// ═══ ⚠⚠ WHERE 251 CAME FROM, AND WHAT IS STILL UNDECIDED ═══
///
/// In the prototype this equalled CHUNK_HEIGHT - 5 = 256 - 5: a VOXEL-COLUMN BUDGET the
/// MESHER owned — the renderable height band, not a fact about the world. Every "420 m peak",
/// "220 m plateau" and "±3 m relief skin" in the generator was therefore denominated in a unit
/// defined by a rendering constant.
///
/// > ### ⚑ HERE IT IS A STANDALONE WORLD CONSTANT.
/// > **Whether it stays coupled to a future chunk height is a DEFERRED DESIGN DECISION for the
/// > vault, and this port does not settle it.** The value 251 is carried because the curve's
/// > anchors were tuned against it and D-050 says port, don't re-derive — not because a
/// > 256-voxel chunk has been decided on. If the vault later rules that the world's vertical
/// > scale is its own number, only this file changes.
///
/// The vault currently records only "roughly 251 m per raw height unit"
/// (`Design - Water - Storm Ladder.md`) and does not record the chunk-height derivation at all.
/// That gap is flagged for graduation, not fixed here — only master writes the vault.
///
public static class WorldScale
{
///
/// Metres of world height per raw height unit.
///
/// ⚠ Ported value, not a re-derivation: the redistribution curve's storm-ladder anchors
/// (420 m cap, 220 m plateau, 100 m bench) were calibrated against exactly this number, so
/// changing it reshapes the island. → D-050.
///
public const float MetresPerRawUnit = 251f;
///
/// The inverse, for callers that genuinely want a multiplier.
///
/// ⚠⚠ NOT INTERCHANGEABLE WITH . In float32,
/// 420f * (1f/251f) and 420f / 251f are DIFFERENT NUMBERS — they differ in the
/// last bits. The reference wrote the division (420f / 251f), so every anchor this
/// repo derives must divide too, or the port is off by an ulp at every knot and no oracle
/// can prove fidelity. Use unless you specifically need the
/// reciprocal.
///
public const float RawUnitsPerMetre = 1f / MetresPerRawUnit;
///
/// Metres → raw height units. **Divides**, bit-for-bit as the reference wrote it
/// (420f / 251f) — see the warning on .
///
public static float RawFromMetres(float metres) => metres / MetresPerRawUnit;
/// Raw height units → metres. The reference's × 251f.
public static float MetresFromRaw(float raw) => raw * MetresPerRawUnit;
/// One line for a run header. Print it; a yardstick worth having is worth stating.
public static string Describe() =>
$"1 raw height unit = {MetresPerRawUnit:F0} m (single source: Core/WorldScale; " +
"chunk-height coupling is a DEFERRED vault decision)";
}
}