Sparse discoverable islets from a low-frequency ocean noise layer, seeded
resolved+7607 at 14 undulations/island (~585 px blobs).
Placed by LERPING the seabed toward a target crest (34 m raw above sea)
rather than adding to it, so an islet can surface at any ambient depth
instead of only where the seafloor happens to be shallow. After the curve's
toe compresses them they stand 5-8 m above the water: low, sandy, ringed by
beach -- which is what the existing biome rules make of that height, with no
biome-rule change.
THE THREE CONSTRAINTS, each by construction rather than by hope:
Never merges with the mainland. The raise is EXACTLY zero wherever the
ambient water is shallower than 14 m, so any continuous path from the
mainland shore to an islet must cross that depth contour, and every pixel
on it is untouched water. Measured: 0 of 13 islets merged, closest
approach 78 px.
Never touches the Trench. A distance mask zeroes the layer by 0.86 of
half-map, and the ramp starts at 0.90. Measured max islet reach 0.795.
All four corners stay below sea.
Never spawns inland. Depth alone is not a test -- a deep lake and the
carved crater bay are also below sea. The pre-Trench falloff is the honest
discriminator (mainland coast sits near f = 0.66; islets need f > 0.72),
and it is axis-invariant, because elongation moves WHERE a given f occurs,
not the f at which land ends.
Two bugs found and fixed by measuring instead of trusting the first run:
1. The density dial treated [-1,1] as the noise's actual range. Simplex
is concentrated well inside it -- this field measures 0.050..0.958 --
so "top 6%" resolved to a threshold almost nothing cleared: the first
build raised 171 px on the entire map, none above sea. The threshold is
now CALIBRATED against the field's own distribution (quantile over a
1M-sample stride grid, deterministic from the seed), so the dial means
what it says whatever FastNoiseLite returns.
2. At 26/island the layer produced 77 islets under 200 px -- scatter, not
"a handful". Retuned to 14/island at density 0.02: 13 islets of
200-4792 px.
The pass prints its own islet area, so every run says what it did.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| Scenes | ||
| Scripts | ||
| README.md | ||
/Tools
Offline developer utilities. Nothing here ships. These generate the source data that /Server
and /Client later consume, which keeps world-generation logic out of the shipped client.
The 2D world generator
Script: Tools/Scripts/MapGenerator.cs · Scenes: Tools/Scenes/MapPreview.tscn and
Scenes/MapCaptureTool.tscn
Builds the topographical and logistical foundation of the island before any 3D exists.
- Resolution is config-driven, from
ServerConfig.json'sMapProfile:4K/6K/8K/10K→ 4096 / 6144 / 8192 / 10240. Shipped default is 8K. 1 pixel = 1 in-game metre = 1 voxel footprint. (TheMapSizefield initialiser in the script says 4096, but it is overwritten from config before use.) - Topography: FastNoiseLite plus distance-falloff maths for a guaranteed mainland island, a mountain spine, dynamic temperature-driven sea level, and an impact crater pushed into the northern coast (carved at 80 % of its radius so a landbridge always survives).
- Water bodies: the classified water promoted into explicit blueprint data (ocean + labeled
lakes with transitional per-body levels —
WBID/WBTB/WSRFsections), plus priority-flood basin diagnostics. TheSkipRoadsconfig toggle turns a full ~26-min generation into a ~80 s road-less iteration cycle. - Logistics:
AStarGrid2Dpathfinding producing a looping continental highway, a branch to the mountain hub, and county roads daisy-chained outward with Prim's algorithm. Paths are decimated (Ramer–Douglas–Peucker) then smoothed (4 Chaikin passes). - Zoning: biome mapping and tiered town/POI placement by slope, temperature and proximity.
⚠️ A* is the known bottleneck
The grid is one node per pixel — 67 million nodes at 8K — and the weight-setup pass walks every
one of them. A full generation can stall long enough that runs get abandoned. await yields are
sprinkled through the road stage, but they cannot interrupt a single engine-side GetPointPath call,
so they only help between paths. Expect a regeneration to take minutes, or to need abandoning.
Outputs — written to user://, not into the project
| File | What it is |
|---|---|
MapData_Seed_<seed>.dat |
The binary blueprint the server reads — v2 tagged container (~336 MB at 8K; contract in Core/Scripts/BLUEPRINT_FORMAT.md) |
MapData_Seed_<seed>_v1.dat |
The same content in the legacy v1 format (~512 MB), dual-written as a safety net until a future removal task |
Map_Seed_<seed>.png |
Visual snapshot of the map, for reviewing and picking seeds |
On Linux: ~/.local/share/godot/app_userdata/islaApocolypse/.
Running it
Open Tools/Scenes/MapPreview.tscn and press F6. It is also the project's main scene, so
pressing F5 anywhere runs this — which is why F5 regenerates your world instead of starting the
game. Use Scenes/MapCaptureTool.tscn when you specifically want the full-resolution PNG.
Rules
- No client dependencies. Nothing here may reference UI, player controllers or shaders in
/Client. - Data out, nothing in. Tools emit
.dat/.png/.json; they never write to a live server save. - No magic numbers. Distances and radii scale off
MapSizeor the derivedscaleFactor, so the generator behaves the same at every profile.