Core/Scripts/RegionLabeling.cs is the shared-infra contract, built to the letter: it runs on the CLASSIFY (raw) field; land is 8-connected, the deliberate complement of water's 4 (a diagonal isthmus joins; the water either side stays separate); a component is a maximal 8-connected set of land cells; the MAINLAND is the component containing the map centre — not merely the largest, which a later fragmentation step could flip — with a flagged fallback to the largest if the centre were ever water (asserted, never needed: oracle m); every other component is an island; per component id / sizeCells / centroid / hemisphere (by centroid, one label per island) / isMainland. Ids come from a fixed scan order and are proven stable across two generations (oracle o, 16.8M cells). It knows nothing about offshore or stamped. Engine-free, in Core as C++-candidate math; the hemisphere convention moved there with it, OffshoreAnalysis aliases it. Tools/Scripts/RegionPass.cs is pass 1c: label, revert, relabel, tag. The island tag (renamed IsIsland; IslandHemisphere from the component's centroid; Pass1Result.Regions carries the whole table) is now a CONSEQUENCE of labeling — every non-mainland component. That is the fix for the chat2/06 overlay, which tagged only what the offshore pass raised: 1063685222 has 11 natural islands including a 94,511-cell detached mass, 20260821 has 19, all grey in 06's tags.png and all coloured now. The offshore pass itself is untouched; its internal Tag stays for its own guards and is no longer exported. The speck revert (TerrainGenConfig.SpeckRevert / MinLandComponentFrac) lowers every non-mainland component below the threshold to the mean of its ring of adjacent sea cells, held strictly below sea. Origin-blind: a natural nub goes the same way as an offshore dot (6 natural components / 273 cells on the bare 1063685222 field at threshold_mid — reported as a3r, informational). Lower-only and component-only are asserted cell by cell in the pass and re-proven on the finished fields by oracle n (mainland bit-identical filter OFF vs ON; every changed cell in a sub-threshold island, lowered below sea); the mainland is never a candidate and its size is asserted unchanged across the revert. A reverted offshore island leaves its submerged skirt as a shoal — not this component, by the rule. Classify/render consistency is by construction (pass 1, curve identity at sea) and asserted by oracle k. Deliberately OFF in the bare TerrainGenConfig for the reason the shelf and islets are: the raw field has natural specks, so default-ON would move the calibration pool and every regression dump; the batch turns it on. Thresholds swept on 8 seeds at 4096 (1e-5 / 3e-5 / 1e-4 of the map = 168 / 503 / 1,678 cells): low removes 0–6 nubs per seed, mid (the config default, equal to the offshore guard) 2–11, high 26–36 — most of the offshore islands, the "fewer, bigger" bookend. The count/size table carries natural / pre / post counts per hemisphere, min/median/mean/max and a log-spaced size histogram — the instrument for the southern-stretch step. Oracle, all passing: a1, a3, a4 (8192, 67M cells) with labeling ON + revert OFF; a6 NEW — labeling ON + revert OFF on the 06 preset bit-identical to the 06 batch's render field (labeling is pure analysis); j0; m, n, o, i, j, k, l, b per field. Batch: BatchRoot(7, "region_labeling") — exactly 4 plates (three thresholds on 1063685222, threshold_mid on 20260821, the table's most-natural-islands seed), each with grayscale / .f32 / relief / the labeled-regions overlay / the tag overlay, plus count_size_table.md/.csv. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013EY3ZTF6NwzF8ukBHQXSK7
70 lines
5 KiB
Markdown
70 lines
5 KiB
Markdown
# Core — math and data only
|
|
|
|
**Holds:** the column model, the material schemas, the scaling discipline, tooling path
|
|
resolution and the file-safety rails. Constants and contracts.
|
|
|
|
**Boundary: Core depends on nothing above it.** Not on `Server/`, not on `Client/`, not on
|
|
`Tools/`. The dependency arrow points one way into this folder and never out of it.
|
|
|
|
> ### ⚠ Additional boundary, tighter than the layer rule: **Core is engine-free.**
|
|
>
|
|
> No `using Godot;` anywhere in this folder. Core is plain C# — no `Node`, no `GD.Print`, no
|
|
> `ProjectSettings`, no engine types in any signature.
|
|
>
|
|
> **Two reasons, both load-bearing.** (1) D-049 commits to *"C# for fast iteration, with C++-ready
|
|
> seams… port path-by-path when settled and hot"* — the hot paths that get ported first are exactly
|
|
> the ones in here, and a type that names `Godot.Vector2` cannot cross that seam. (2) It keeps the
|
|
> column model testable and reviewable without standing up an engine.
|
|
>
|
|
> Where Core genuinely needs something the engine knows — the resolved `user://` directory — the
|
|
> engine layer **hands it in** (`ToolingPaths.Configure`), rather than Core reaching for it.
|
|
> If you find yourself wanting an engine type here, the type belongs one layer up.
|
|
|
|
## What is in here
|
|
|
|
| File | What it is |
|
|
|---|---|
|
|
| `Scripts/Column.cs` | ★★ **The load-bearing contract** (D-053). A column as run-length bands; `MaterialRun`; `RunOrigin`. Read its header before touching anything that stores world data. |
|
|
| `Scripts/ColumnGrid.cs` | The 2D grid of columns. Shape only — chunking and streaming are later phases. |
|
|
| `Scripts/MaterialKey.cs` | Material **identity** — a registry key, never an ordinal. |
|
|
| `Scripts/TerrainMaterial.cs` | A row in the terrain schema (D-054). |
|
|
| `Scripts/BuildingMaterial.cs` | A row in the building schema (D-054). |
|
|
| `Scripts/MaterialRegistry.cs` | Both registries, append-only, seed rows only. |
|
|
| `Scripts/RecipeRegistry.cs` | The transformation seam — **deliberately empty**. |
|
|
| `Scripts/GenerationScale.cs` | ⭐ The scaling discipline. `MapSize`, `ScaleFactor`, normalized offsets, the two frequency conventions. |
|
|
| `Scripts/WorldScale.cs` | ⭐ **The vertical yardstick.** The ONE metres↔raw conversion (251 m/unit). No literal `251f` anywhere else. |
|
|
| `Scripts/HeightCurve.cs` | ⭐⭐ The height-redistribution curve (v5), 7 bands. **Identity at and below sea.** |
|
|
| `Scripts/CurveKnots.cs` | The six INPUT knots — percentiles of the measured land CDF, plus the reference's for comparison. |
|
|
| `Scripts/CurveAnchors.cs` | The OUTPUT anchors — the storm-ladder elevations each band lands at. |
|
|
| `Scripts/TerrainDetailPass.cs` | Shelf micro-relief + the shelf-edge **knot warp**. Output-height only. |
|
|
| `Scripts/RegionLabeling.cs` | ⭐⭐ **The region-labeling layer** (chat2/07) — shared infrastructure. 8-connected land components on the CLASSIFY field; mainland = the centre component; per component id / size / centroid / hemisphere (by centroid) / isMainland. Pure, engine-free, C++-candidate; a **contract** downstream phases consume (islands first; biomes, placement, rivers, the crater later). The hemisphere convention lives here. |
|
|
| `Scripts/ToolingPaths.cs` | Every tooling path, env-overridable, resolved in one place. |
|
|
| `Scripts/FileSafety.cs` | The permanent file-safety rules, as throws rather than sentences. |
|
|
|
|
## The three rules this layer exists to make unbreakable
|
|
|
|
1. **Air is the top run.** There is no "air vs solid" height branch, anywhere, ever.
|
|
→ `Scripts/Column.cs`.
|
|
2. **Properties come from the registry, never from storage.** A run stores an identity.
|
|
→ `Scripts/MaterialRegistry.cs`.
|
|
3. **Nothing uses a raw pixel number.** Every distance is a fraction of `MapSize`.
|
|
→ `Scripts/GenerationScale.cs`.
|
|
4. **There is one metres-per-raw-unit number.** The prototype scattered `251` across three
|
|
duplicate constants and ~20 literals, and the generator never used the derived one at all.
|
|
→ `Scripts/WorldScale.cs`.
|
|
|
|
## Not here, and not by accident
|
|
|
|
- **No water.** Water is an overlay over the columns (levels-not-cells), never a band.
|
|
- **No biomes.** Biomes are a later *classification* of finished shape, not an input to it (D-049).
|
|
- **No algorithms** *beyond the height curve and the region layer*. Phase 2 added `HeightCurve` and
|
|
`TerrainDetailPass` here because they are pure, engine-free, C++-candidate math that defines the
|
|
world's elevation profile — a contract, not a tool's dial. chat2/07 added `RegionLabeling` on the
|
|
same grounds: region identity is a contract every later phase reads, and the flood fill is a hot
|
|
path. (The speck REVERT that uses it is a pass, and lives in `Tools/` — `RegionPass`.) Stratigraphy, feature passes, meshing
|
|
and run-splitting on dig are still later phases.
|
|
- **No erosion, rivers, water bodies, crater carve, coast shelf or offshore islets.** Later chat2
|
|
tasks; the curve is deliberately the only pass-2 element present.
|
|
|
|
→ `Design - Data - Column Model.md`, `Design - Data - Material Schema.md`,
|
|
`Design - Tooling - Scaling Discipline.md`
|