Config flag SkipRoads (default false): when on, GenerateRoadsAsync and
the 3_roads snapshot are skipped entirely; export proceeds with all
four road sections present but empty (both v2 and legacy v1 permit
zero counts); the console states loudly that the blueprint is a
road-less iteration artifact.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v2 tagged-section container (D-030): raw ISLA magic + u32 version gate,
[u32 tag][u64 length][payload] sections — params (resolved generation
inputs incl. impact centre), heights f32, biomes u8, towns with the
highway-node flag, four road tiers identified by tag not position.
- BlueprintFormat.cs: the single tag/constant registry.
- BlueprintWriter.WriteV2: blueprint-typed, callable outside a
generation run; generator and harness are both just callers.
- ExportMapData dual-writes: v2 under the primary seed name, legacy v1
beside it as _v1.dat (safety net; removal is a future task).
- MapDataParser: LoadMapDataFromPath entry point; v1 parse body
extracted intact as LoadV1 (v2 reader lands in the next commit).
- RoundTripHarness scene: load v1 -> write v2 -> load v2 -> semantic
equality, headless, seconds per cycle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two additions, both observability only — no generation, routing, weight,
terrain or mesher behaviour changes.
1. Every progress print is now prefixed with elapsed time since generation
started, e.g. [+ 142.7s], including a line per pipeline stage and per county
road. The per-stage split (setup / continental loop / branch / county) can
now be read straight off the console. Two A* fix attempts have been reasoned
from structure rather than measurement; this makes the measurement free.
2. The end-of-run PNG capture was extracted into a reusable stage capture that
can be called at any pipeline boundary. Snapshots are now taken after
biomes, after towns, and after roads. The draw proxy renders whatever exists
at the time, so stages that have not run simply do not appear — and a future
water stage will show up automatically once it populates its data.
The existing capture path is reused unchanged: same offscreen SubViewport,
same draw proxy, same frame-yield plus double GPU wait. Those waits are
load-bearing, not superstition, and each staged capture honours them.
Snapshot filenames gain a stage suffix: Map_Seed_<seed>_1_biomes.png,
_2_towns.png, _3_roads.png. Nothing reads these but a human, verified.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A* was searching almost the whole island for every road. Godot's stock
estimate-to-goal is plain straight-line distance, which assumes every step
costs 1 — but a step through mountains costs up to 401 and a step near an
existing road cost 10,001. With the estimate that far below reality, A* cannot
rule anything out, so it degenerates toward Dijkstra.
Two changes, both aimed at that:
1. RoadPathGrid overrides the estimate to scale it by HEURISTIC_WEIGHT (3.0),
i.e. weighted A*. Paths may be up to 3x costlier than the theoretical best
in exchange for exploring far less. This does NOT push roads over mountains:
a ridge costs hundreds of times more than going around, which a 3x bias
nowhere near pays for.
2. ROAD_REPULSION_PENALTY replaces the hardcoded +10000 with 250. The old value
made ground near a road effectively infinite, and it compounded — each road
drawn made the next search slower. 250 still strongly discourages roads from
running alongside each other.
Terrain weights are untouched: the mountain curve (1 + elevation^3 * 400),
beach and wasteland costs are exactly as before, so mountains remain expensive
and roads still avoid them. Routing, tiers, smoothing and grid resolution are
also unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every road path search — highway, branch, county — now goes through one
function instead of three direct GetPointPath calls. The function body is
exactly the call it replaced, so behaviour is unchanged.
This exists so the next commit's pathfinding change can be judged on its own:
if the generated map changes after this point, it was the heuristic, not a
refactor slip.
Routing is untouched: which towns connect, loop order, Prim's daisy-chain,
tier assignment and the abandon protocol all deal only in town positions and
never touch the grid.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>