docs: bring all READMEs current with actual code (post-sweep-10 truth pass)
Every README was read first, checked against the code in its directory, then rewritten to describe what the code actually does now. Corrected throughout: map size is config-driven (8192 default) not a fixed 4096; chunks are 24x24x256 not 32x32; road carving is implemented for all four tiers, not a 'next step'; Data/ and Resources/ are empty, not populated. Also fixed MATH_MARCHING_CUBES.md, which documented the density sign convention exactly backwards — it claimed positive was underground, where the code treats positive as above the surface and counts a corner inside when density < iso. Getting that backwards inverts every normal, a bug this project has hit before. The root README now carries accurate run steps: F5 runs the map generator (not the game), F6 on Scenes/Main.tscn runs the 3D world, and ChunkRadius is a load radius that should be dropped to 4-8 while iterating. Docs only. No code changed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f9ea2da3f4
commit
d72ffc0183
13 changed files with 579 additions and 409 deletions
|
|
@ -1,7 +1,17 @@
|
|||
# MapGenerator.cs - Architecture & Historical Decisions
|
||||
|
||||
**Date:** March 2026
|
||||
**Purpose:** Generates a 4096x4096 2D topographical blueprint (Topography, Biomes, Cities, and Road Networks) to be parsed and translated into a 3D Voxel World.
|
||||
**Purpose:** Generates the 2D topographical blueprint (Topography, Biomes, Cities, and Road Networks)
|
||||
to be parsed and translated into a 3D Voxel World.
|
||||
|
||||
> ⚠ **Historical document — read it as a record of decisions, not as current spec.** It was written
|
||||
> when the map was 4096², and references to that size throughout should be read as "the map size of
|
||||
> the day". **Map size is now config-driven** (`MapProfile` in `ServerConfig.json`; 8192 by default),
|
||||
> and the reasoning it describes — scaling everything off `MapSize` rather than hardcoding — is
|
||||
> exactly what makes that work.
|
||||
>
|
||||
> For the current behaviour see `Tools/Scripts/README.md`. For design rationale and the decisions
|
||||
> behind the project, see the design vault.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,61 @@
|
|||
# 📜 /Tools/Scripts - Generation Logic
|
||||
|
||||
## Overview
|
||||
This directory contains the raw C# backend logic for all of our offline developer tools. These scripts are strictly for generating source data (Maps, Prefabs, Balance Configs) and are completely decoupled from the live game server and client.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Core Scripts
|
||||
|
||||
### `MapGenerator.cs`
|
||||
**The Master World Builder.** This script is responsible for generating the 2D topographical and logistical blueprint of *Isla Apocalypse*. It runs FastNoiseLite math, calculates distance falloffs, plots A* road networks, and zones the biomes.
|
||||
|
||||
#### ⚔️ The Great 4096 Struggle (The 1:1 Scale Transition)
|
||||
Originally, this script generated a 1024x1024 map where 1 pixel equaled 1 chunk (4 meters). To accommodate industry-standard human-scale base building, we transitioned the engine to a 1:1 scale (1 pixel = 1 meter), effectively quadrupling the map size to 4096x4096.
|
||||
|
||||
This transition broke almost everything, requiring a massive architectural overhaul:
|
||||
|
||||
1. **The "TV Static" Math Fix:** Multiplying the map size by 4 caused the noise generator to pack 4 kilometers of terrain into 1 kilometer of space, creating visual static. We introduced a dynamic `scaleFactor` (`MapSize / 1024f`) to stretch the noise frequency back out, preserving the massive, sweeping "chonky" biomes while maintaining the 1:1 scale.
|
||||
2. **Eradicating Magic Numbers:** Hardcoded pixel checks (e.g., "check 10 pixels for water") were completely broken by the upscaling. We refactored the logic to use dynamic map percentages for slope checking, water detection, and A* highway repulsion.
|
||||
3. **The 1KB Postage Stamp (Defeating the UI Engine):** Trying to capture a 4096 image inside a standard Godot UI layout node resulted in the engine crushing the map into a tiny 1KB square. To fix this, `SaveMapSnapshot()` was rewritten to build an invisible, offscreen `SubViewport` entirely in C#.
|
||||
4. **The Draw Proxy:** Because raw `Texture.GetImage()` does not capture Godot's `_Draw()` functions, we created `MapDrawProxy`. This stamps the colored roads and towns onto the offscreen monitor. We then implemented asynchronous thread-locking (`await ToSignal(RenderingServer...)`) to force the code to wait for the GPU to physically paint the roads before snapping the PNG.
|
||||
|
||||
**Outputs:**
|
||||
* `MapData_Seed_[X].dat` - The binary map data for the Server.
|
||||
* `Map_Seed_[X].png` - The 4096 high-resolution visual render.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Scripting Rules
|
||||
1. **No Magic Numbers:** Any distance, radius, or length must be calculated as a percentage of `MapSize` or use the `scaleFactor`.
|
||||
2. **GPU Respect:** Any script exporting visual data must use `CallDeferred` or `await` frames to ensure the Godot rendering engine has finished processing.
|
||||
# /Tools/Scripts — generation logic
|
||||
|
||||
C# backend for the offline developer tools. Decoupled from the live server and client.
|
||||
|
||||
## `MapGenerator.cs`
|
||||
|
||||
Generates the entire 2D blueprint. Roughly in order:
|
||||
|
||||
1. **Config** — reads `ServerConfig.json`, which sets `MapSize` (8192 by default) and the crater
|
||||
radius. The `MapSize = 4096` field initialiser is a fallback that is immediately overwritten.
|
||||
2. **Topography** — FastNoiseLite base height plus a mountain spine, minus a squircle distance
|
||||
falloff, giving a guaranteed island. Noise frequency is divided by `scaleFactor`
|
||||
(`MapSize / 1024f`) so terrain features stay the same real-world size at any map profile.
|
||||
3. **Sea level and water** — temperature-driven sea level; flood fill separates true ocean from
|
||||
inland lakes; a mainland fill guarantees one contiguous landmass.
|
||||
4. **The crater** — placed along the northern coast and carved to below sea level, but only out to
|
||||
**80 % of its radius**, which guarantees a landbridge rather than severing the island.
|
||||
5. **Biomes and towns** — biome zoning by height and temperature; tiered town placement (Capitol,
|
||||
Hubs, Villages, Outposts, POIs) filtered by slope, water proximity and spacing.
|
||||
6. **Roads** — see below.
|
||||
7. **Export** — writes the `.dat` blueprint, then renders the PNG snapshot.
|
||||
|
||||
### The road network
|
||||
|
||||
`AStarGrid2D` over the whole map at one node per pixel. Mountains are made expensive rather than
|
||||
impassable (`1 + elevation³ × 400`), water and the crater are marked solid.
|
||||
|
||||
- **Continental loop** — highway nodes sorted by radial angle and connected in a ring.
|
||||
- **Mountain branch** — a spur from the loop to the snow hub.
|
||||
- **County roads** — Prim's algorithm daisy-chains remaining towns onto the network. Villages become
|
||||
Rugged roads, everything else Trails.
|
||||
- **Abandon protocol** — a town further than 8 % of the map from the network is skipped rather than
|
||||
pathed to, so one unreachable outpost cannot hang generation.
|
||||
- **Smoothing** — every path is decimated with Ramer–Douglas–Peucker (tolerance 4.0) then smoothed
|
||||
with 4 Chaikin passes.
|
||||
|
||||
⚠ **This is the project's dominant performance problem.** At 8K the grid is 67 million nodes, and the
|
||||
weight-setup pass touches every one before the first path is requested. The `await` yields between
|
||||
stages cannot interrupt a single engine-side `GetPointPath` call, so a long path still blocks. Full
|
||||
regenerations frequently get abandoned.
|
||||
|
||||
### The PNG snapshot
|
||||
|
||||
`SaveMapSnapshot()` builds an offscreen `SubViewport` in code rather than relying on the scene's
|
||||
layout, because Godot's UI layout engine will otherwise crush a 4096+ render down to the editor
|
||||
window size. A `MapDrawProxy` control re-issues the `_Draw()` calls into that viewport — `GetImage()`
|
||||
captures only the base texture and would otherwise miss the roads and towns entirely — and the code
|
||||
awaits two `RenderingServer.FramePostDraw` signals so the GPU has actually painted before the image
|
||||
is read back.
|
||||
|
||||
Road colours on the snapshot, useful for identifying a road: **red** = Highway, **black** = Branch,
|
||||
**dark brown** = Rugged, **light brown** = Trail.
|
||||
|
||||
### Outputs
|
||||
`MapData_Seed_<seed>.dat` and `Map_Seed_<seed>.png`, both to `user://`.
|
||||
|
||||
## Rules
|
||||
1. **No magic numbers.** Distances, radii and thresholds derive from `MapSize` or `scaleFactor`, so
|
||||
the generator behaves identically at 4K and 10K.
|
||||
2. **Respect the GPU.** Anything exporting visual data must `await` the appropriate frame signals
|
||||
before reading pixels back.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue