feat(shared): compute topographic prominence over a height grid #7
No reviewers
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
scope/assets
scope/client
scope/networking
scope/renderer
scope/scripting
scope/server
scope/shared
scope/workspace
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Synvael/synvael!7
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/landform-prominence"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What does this PR do?
I added
shared::world::prominence, which computes topographic prominence over a plain height grid.HeightGridholds one surface height per column, indexed x-major.compute_prominencesweeps columns in descending height order with a union-find and returns everySummitwith itsProminence, sorted by grid index.summits_at_or_abovefilters 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::Clippedinstead of a number.summits_at_or_abovenever 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.datv1 migration fromshared::save::level.decodeno longer takes a legacy config and refuses format version 1 withSaveError::UnsupportedVersion.WorldMetadataV1andLEGACY_WORLD_FORMAT_VERSIONnow live only incrates/shared/src/tests/level.rsto build the bytes forrejects_a_legacy_record. I updatedcrates/server/src/save/level_file.rsandcrates/shared/examples/inspect_save.rsto the new signature, and the example no longer readsassets/data/worldgen/default/0.json.I also deleted
CLAUDE.mdand inlined theAGENTS.local.mdimport inAGENTS.mdas a plain instruction.Why is this change necessary?
TODO: say why landform placement needs prominence. Nothing calls
compute_prominenceyet, 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
decodehad to supply a legacy config it had no other use for.Scope of Changes
server, shared, workspace
Testing
Automated, run on
feat/landform-prominenceat396b3a2: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.rsadds 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_recordreplaces the old migration test.No Lua changed. I did no manual verification.
Additional Context
level.datstays atWORLD_FORMAT_VERSION = 2. A v1 file now fails to load and the server does not regenerate it, sinceload_or_createtreats an unparseable file as an error.The prominence code sits in
sharedwith 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
dev(or a feature branch offdev) and my PR targetsdev.///doc comments for Rust) where necessary.