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)"; } }