feat(mapeditor): Route roads by slope, carving walkable switchbacks into steep terrain #267
No reviewers
Labels
No labels
alpha:wave-0
alpha:wave-1
alpha:wave-2
alpha:wave-3
area:assets
area:combat
area:ecology
area:infra
area:render
area:scripting
area:ui
area:world
enhancement
epic
migration
post-alpha
roadmap
tech-debt
type:bug
type:chore
type:design
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
marco/IsoMmo!267
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/road-router"
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?
Summary
Roads drawn in the editor were impassable on real elevation. The first attempt graded a straight Z-ramp between the two ends; on a slope steeper than
length × MaxWalkStepZno such ramp stays walkable AND touches the ground at both ends, so an end floated and the road was unreachable. Following the ground exactly (no Z change) fixed floating but left steep mountains impassable — there's no walkable way straight up a cliff.Taking inspiration from reality (a real mountain road is cut into the hillside with switchbacks), Route now carves. You lay a road two ways:
(cell, roadZ). From a cell at road heightzit may move to a buildable neighbour at any road height within±MaxWalkStepZofz(the server'sCanStepgrade) AND within±Carveof that neighbour's existing ground (the earthwork budget). Cost = horizontal distance + a penalty per Z of cut/fill, so the road hugs the ground where it can and only carves to hold the grade — long, terrain-hugging switchbacks emerge on steep faces. Both ends sit on the existing ground; the carved Z is stamped along the path. A Carve slider (default 30) sets how deep it may cut/fill — raise it to climb steeper faces. If no walkable road fits even so (e.g. a one-cell vertical cliff, where cut + fill still leaves a step) the map is left untouched and the readout says so.This re-introduces controlled Z-writing for roads (bounded by Carve), superseding the earlier "roads never touch Z" step — a deliberate reversal after testing showed dramatic mountains need earthworks, exactly like real roads. A gentle slope carves nothing, so the carving router subsumes a plain terrain-following road.
Follow-up (not in this PR): tunnels / mines need a multi-level world model (more than one walkable Z per cell) — the current map is a single-Z heightfield. That's a foundational epic, tracked separately; this PR stays surface-only.
Screenshots / recording
The visible surface is the map editor (a MonoGame desktop app) and Route is a two-click GUI interaction on a slope — the debug harness drives the game client over TCP, not the editor's mouse/ImGui, so it can't reach this state headlessly (noted, not faked). Behaviour is pinned by unit tests (below). I can produce an in-game walk-through if a routed switchback is painted and the world Saved — then I drive the client up it from a fresh DB.
How it was tested
RoadRouterTests(10 cases): start==end → a single point on the ground; flat → shortest diagonal, zero carve; a walkable slope followed with zero carve; both ends sit on the existing ground; a steep face (8/cell) climbed by a longer, carved switchback (path length > straight, every step within grade, every cut ≤ Carve, reaches the top); a one-cell vertical cliff can't be bridged within the budget → null; unbuildable endpoint → null; exhausted search budget → null; deterministic.dotnet test tests/IsoMmo.MapEditor.Core.Tests→ 70/70 green, 0 warnings (warnings-as-errors).dotnet build tools/IsoMmo.MapEditor→ 0 warnings / 0 errors.dotnet csharpier check .→ clean (515 files, full output).python scripts/check-doc-refs.py→ resolves.Design review — persisted Invariants Check
Editor-tool change; most gameplay invariants N/A (each falsifiable).
CanStep, which the router uses as its edge gate, so a routed road can't be one the server rejects. · GM auth / Identity / Protocol / String catalog N/A. · Single-threaded sim /World.csgate N/A (tool, noWorld). ·Screengate ✓ logic in pureRoadRouter(Core);EditorGamecoordinates clicks → router → stamp. · Client engine-independence ✓RoadRouterpure inMapEditor.Core, unit-tested. · Act on the instance ✓ pure function; no side-collection (readsZAt/TerrainIdAt, writesSetTerrain/SetZ). · Extend by type ✓ one algorithm, no switch. · Persistence (GameServer) ✓ carved Z persists via the existing chunked format (like any Raise/Set Z); no format change. · Persistence (Auth) / Process separation N/A. · Typed options ✓CarvePenalty/budget are named consts; Carve is a bounded editor field; reusesWorldRules.MaxWalkStepZ. · Broadcasts/AoI / Assets / Asset naming N/A. · ModernUO standard grid A* over the existing UO-style step-height gate; the multi-level model tunnels would need is called out as the separate epic. · Docs & DoD same change ✓docs/map-editor.mdroad section rewritten here.No
✗, no HARD GATE tripped.Definition of Done
MaxWalkStepZand every cut/fill within Carve, both ends on the existing ground — walkable in-game end-to-end, including a switchback on a face too steep to climb head-on.RoadRouterTestsassert the grade+carve invariants on every returned step, the switchback lengthening, the vertical-cliff null, and determinism.Checklist
just lintpasses (CSharpier clean + affected projects build, zero warnings)just testgreen for the affected project (70/70)RoadRouterTests, 10 cases)Supersedes #266 (the Z-ramp grader), which is closed.
feat(mapeditor): route roads by slope (walkable A→B pathing); roads no longer terraform Zto feat(mapeditor): Route roads by slope, carving walkable switchbacks into steep terrainpanda referenced this pull request2026-08-03 13:24:35 +02:00