feat(shared): compute topographic prominence over a height grid #7

Merged
Serkyo merged 5 commits from feat/landform-prominence into dev 2026-09-25 17:23:14 +00:00
Owner

What does this PR do?

I added shared::world::prominence, which computes topographic prominence over a plain height grid. HeightGrid holds one surface height per column, indexed x-major. compute_prominence sweeps columns in descending height order with a union-find and returns every Summit with its Prominence, sorted by grid index. summits_at_or_above filters that list to summits at or above a threshold, ordered by descending prominence with ties broken by index.

Columns of equal height are processed as one run, so a plateau of any shape, rings included, counts as a single summit reported at its lowest index. A second commit on the branch fixed the first version, which decided summits and clipping per column and so could report a flat corner as a summit of prominence zero. Summits and clipping are now decided per component.

The grid is a window onto a larger world, so a summit whose component reaches the grid edge above the height where it is finalized is reported as Prominence::Clipped instead of a number. summits_at_or_above never returns clipped summits. The global maximum is clipped if it touches the edge at its own height, and otherwise measures its height above the grid's lowest column.

In the same branch I removed the level.dat v1 migration from shared::save::level. decode no longer takes a legacy config and refuses format version 1 with SaveError::UnsupportedVersion. WorldMetadataV1 and LEGACY_WORLD_FORMAT_VERSION now live only in crates/shared/src/tests/level.rs to build the bytes for rejects_a_legacy_record. I updated crates/server/src/save/level_file.rs and crates/shared/examples/inspect_save.rs to the new signature, and the example no longer reads assets/data/worldgen/default/0.json.

I also deleted CLAUDE.md and inlined the AGENTS.local.md import in AGENTS.md as a plain instruction.

Why is this change necessary?

TODO: say why landform placement needs prominence. Nothing calls compute_prominence yet, so the diff itself does not show the motivation.

The v1 migration covered a format that no world outside my dev machine was ever written in. Keeping it meant every caller of decode had to supply a legacy config it had no other use for.

Scope of Changes

server, shared, workspace

Testing

Automated, run on feat/landform-prominence at 396b3a2:

  • cargo check -p shared -p server: passed.
  • cargo test -p shared -p server: passed, 307 tests across both crates, 0 failures.
  • cargo clippy --all-targets --all-features -- -D warnings: passed.
  • cargo fmt --all -- --check: passed.

crates/shared/src/tests/world_prominence.rs adds 12 tests covering a lone peak, two peaks across a saddle, edge summits, clipping when the descent leaves the grid above or below the saddle, square and ring plateaus, a monotone slope, equal-height tie-breaking, order independence, the inclusive threshold, and threshold ordering. rejects_a_legacy_record replaces the old migration test.

No Lua changed. I did no manual verification.

Additional Context

level.dat stays at WORLD_FORMAT_VERSION = 2. A v1 file now fails to load and the server does not regenerate it, since load_or_create treats an unparseable file as an error.

The prominence code sits in shared with no new dependencies and stays deterministic: the sweep order and the output order both break ties on grid index, and it uses no hashed collections.

N/A

Checklist

  • I have branched from dev (or a feature branch off dev) and my PR targets dev.
  • I have kept my changes focused to a single concept.
  • I have added or updated documentation (/// doc comments for Rust) where necessary.
  • I have tested my changes and described any relevant automated or manual testing above.
### What does this PR do? I added `shared::world::prominence`, which computes topographic prominence over a plain height grid. `HeightGrid` holds one surface height per column, indexed x-major. `compute_prominence` sweeps columns in descending height order with a union-find and returns every `Summit` with its `Prominence`, sorted by grid index. `summits_at_or_above` filters that list to summits at or above a threshold, ordered by descending prominence with ties broken by index. Columns of equal height are processed as one run, so a plateau of any shape, rings included, counts as a single summit reported at its lowest index. A second commit on the branch fixed the first version, which decided summits and clipping per column and so could report a flat corner as a summit of prominence zero. Summits and clipping are now decided per component. The grid is a window onto a larger world, so a summit whose component reaches the grid edge above the height where it is finalized is reported as `Prominence::Clipped` instead of a number. `summits_at_or_above` never returns clipped summits. The global maximum is clipped if it touches the edge at its own height, and otherwise measures its height above the grid's lowest column. In the same branch I removed the `level.dat` v1 migration from `shared::save::level`. `decode` no longer takes a legacy config and refuses format version 1 with `SaveError::UnsupportedVersion`. `WorldMetadataV1` and `LEGACY_WORLD_FORMAT_VERSION` now live only in `crates/shared/src/tests/level.rs` to build the bytes for `rejects_a_legacy_record`. I updated `crates/server/src/save/level_file.rs` and `crates/shared/examples/inspect_save.rs` to the new signature, and the example no longer reads `assets/data/worldgen/default/0.json`. I also deleted `CLAUDE.md` and inlined the `AGENTS.local.md` import in `AGENTS.md` as a plain instruction. ### Why is this change necessary? TODO: say why landform placement needs prominence. Nothing calls `compute_prominence` yet, so the diff itself does not show the motivation. The v1 migration covered a format that no world outside my dev machine was ever written in. Keeping it meant every caller of `decode` had to supply a legacy config it had no other use for. ### Scope of Changes server, shared, workspace ### Testing Automated, run on `feat/landform-prominence` at `396b3a2`: - `cargo check -p shared -p server`: passed. - `cargo test -p shared -p server`: passed, 307 tests across both crates, 0 failures. - `cargo clippy --all-targets --all-features -- -D warnings`: passed. - `cargo fmt --all -- --check`: passed. `crates/shared/src/tests/world_prominence.rs` adds 12 tests covering a lone peak, two peaks across a saddle, edge summits, clipping when the descent leaves the grid above or below the saddle, square and ring plateaus, a monotone slope, equal-height tie-breaking, order independence, the inclusive threshold, and threshold ordering. `rejects_a_legacy_record` replaces the old migration test. No Lua changed. I did no manual verification. ### Additional Context `level.dat` stays at `WORLD_FORMAT_VERSION = 2`. A v1 file now fails to load and the server does not regenerate it, since `load_or_create` treats an unparseable file as an error. The prominence code sits in `shared` with no new dependencies and stays deterministic: the sweep order and the output order both break ties on grid index, and it uses no hashed collections. ### Related Issues N/A ### Checklist - [x] I have branched from `dev` (or a feature branch off `dev`) and my PR targets `dev`. - [x] I have kept my changes focused to a single concept. - [x] I have added or updated documentation (`///` doc comments for Rust) where necessary. - [x] I have tested my changes and described any relevant automated or manual testing above.
docs(workspace): drop CLAUDE.md now that AGENTS.md loads natively
All checks were successful
Auto Labeler / label-scope (pull_request_target) Successful in 2s
CLA Signed All authors have signed the CLA.
CLA Check / cla-check (pull_request_target) Successful in 2s
CI / Rust Check, Lint & Test (pull_request) Successful in 34m37s
CI / Dependency Licenses & Advisories (pull_request) Successful in 27s
CI / Lua Lint & Format (pull_request) Successful in 6s
CI / Commit Message Lint (pull_request) Successful in 2s
CI / LFS Pointer Guard (pull_request) Successful in 5s
396b3a2611
Serkyo deleted branch feat/landform-prominence 2026-09-25 17:23:14 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Synvael/synvael!7
No description provided.