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:
Stewart Howe 2026-08-05 05:23:58 -04:00
parent f9ea2da3f4
commit d72ffc0183
13 changed files with 579 additions and 409 deletions

View file

@ -1,52 +1,52 @@
# 🧰 Tools Directory - Isla Apocalypse
## Overview
The `/Tools` directory houses all offline developer utilities, administrative scenes, and generation scripts.
**Core Philosophy:** Nothing in this folder is shipped to the end-user. These tools are used exclusively by the developers or server admins to generate the immutable "Source Data" (blueprints, prefabs, configs) that the `/Server` and `/Client` will later ingest. By keeping this logic completely isolated, we ensure the game client remains lightweight and secure from reverse-engineered world-generation exploits.
---
## 🛠️ Current Tools
### 1. The 2D World Generator (`MapCaptureTool.tscn` & `MapPreview.tscn`)
**Status:** Active / Upgraded to 1:1 Scale Architecture
This tool handles the heavy mathematical lifting of procedural generation. It creates the topographical and logistical foundation of the island before any 3D rendering occurs.
* **Primary Script:** `MapGenerator.cs`
* **Resolution:** 4096 x 4096 pixels (1:1 Scale. 1 Pixel = 1 In-Game Meter / 1 Voxel footprint).
* **Capture Architecture:** Uses a dynamic, C#-driven offscreen `SubViewport` and a custom `MapDrawProxy`. This bypasses Godot's UI layout engine, allowing the generation of massive, high-resolution maps regardless of the developer's physical monitor size.
* **Key Sub-Systems:**
* *Topography:* Uses `FastNoiseLite` and distance-falloff math to guarantee a mainland island shape with cold/mountainous northern regions.
* *Logistics:* A* Pathfinding that generates looping coastal highways, connecting branch roads, and rugged mountain trails. Pathing is dynamically scaled to the map resolution.
* *Zoning:* Biome mapping and hierarchical Town/POI placement based on slope, temperature, and proximity.
**Outputs (Saved to `user://`):**
1. **The Blueprint (`MapData_Seed_[X].dat`):** A heavily compressed binary file containing the map size, heightmap floats, biome enums, road vectors, and POI coordinates. This is the master file read by the Dedicated Server.
2. **The Snapshot (`Map_Seed_[X].png`):** A high-resolution 1:1 visual render of the map layout (including all drawn logistical routes) for admin review and seed selection. Timestamps have been removed to prevent directory bloating.
---
## 🚀 Future Roadmap & Planned Additions
As we move into Phase 2 (3D Voxels) and Phase 3 (Gameplay), this directory will expand to include the following standalone utilities:
### 2. The Prefab Editor (Planned - Phase 3)
A standalone 3D sandbox scene used to build custom Points of Interest (POIs) block-by-block (e.g., houses, bunkers, gas stations).
* **Function:** Allows the developer to build structures visually and define "Loot Container" or "Zombie Spawn" block locations.
* **Output:** Generates lightweight `.prefab` or `.json` files that the Server's Chunk Manager reads to spawn buildings at the coordinates dictated by the `MapData.dat` file.
### 3. Voxel Palette Manager (Planned - Phase 2)
A data-entry tool or inspector script to map 2D Biome Enums to 3D Voxel IDs.
* **Function:** Defines that `Biome.Jungle` at `Height 0.5` should spawn "Voxel ID 12 (Jungle Grass)", while `Height 0.2` should spawn "Voxel ID 4 (Dirt)".
### 4. Loot & Balance Tweaker (Planned - Phase 3)
A simple UI tool to adjust spawn weights and loot tables without having to dig through massive JSON files manually.
* **Output:** Bakes final configuration files for the Server to use when rolling loot table RNG.
---
## ⚠️ Directory Rules
1. **No Client Dependencies:** Scripts in this folder must *never* reference UI, Player Controllers, or Shaders located in the `/Client` folder.
2. **Data Agnostic:** Tools here should output raw data (`.dat`, `.json`, `.png`). They should not directly modify the live server's save state to avoid corruption.
# /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`'s `MapProfile`: `4K`/`6K`/`8K`/`10K` →
4096 / 6144 / 8192 / 10240. **Shipped default is 8K.** 1 pixel = 1 in-game metre = 1 voxel
footprint. (The `MapSize` field 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).
- **Logistics:** `AStarGrid2D` pathfinding 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 (~512 MB at 8K) |
| `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
1. **No client dependencies.** Nothing here may reference UI, player controllers or shaders in
`/Client`.
2. **Data out, nothing in.** Tools emit `.dat`/`.png`/`.json`; they never write to a live server save.
3. **No magic numbers.** Distances and radii scale off `MapSize` or the derived `scaleFactor`, so the
generator behaves the same at every profile.

View file

@ -1,47 +1,37 @@
# 🎬 /Tools/Scenes - Developer Environments
## Overview
This directory contains the standalone Godot scenes (`.tscn` files) used to execute our offline generation scripts. These scenes act as isolated "sandboxes" for the developers to build the world data.
**CRITICAL RULE:** These scenes must **never** be added to the main game's build export or scene tree. They are run strictly inside the Godot Editor by pressing **F6 (Play Current Scene)**.
---
## 🏗️ Core Scenes
### 1. `MapPreview.tscn`
The original 2D map generation scene.
* **Root Node:** `TextureRect`
* **Attached Script:** `MapGenerator.cs`
* **Function:** Runs the FastNoiseLite math, builds the `_heightMap`, and executes the `_Draw()` commands to visually plot the A* road networks and town circles.
### 2. `MapCaptureTool.tscn` (The Wrapper)
The master scene used to actually execute and capture the map generation.
* **Root Node:** `SubViewportContainer`
* **Child Nodes:** `SubViewport` -> `MapPreview`
* **Function:** Acts as a massive, invisible "virtual monitor" to capture the high-resolution PNG of the map without the Godot UI layout engine interfering.
---
## ⚔️ The Great 4096 Struggle (Beating the UI Engine)
When we upgraded *Isla Apocalypse* from a 1024 to a 4096 (1:1 scale) map, we encountered a massive rendering roadblock. Godot's UI Layout Engine is designed to make things fit on a player's physical monitor.
When we asked `MapPreview` to render a 4096x4096 texture, Godot panicked. It saw that the developer's monitor was only 1080p, so it violently crushed the map down to fit the screen, resulting in exported PNGs that were either 1KB postage stamps or completely black.
#### The "Virtual Monitor" Solution
To bypass the UI engine, we had to build `MapCaptureTool.tscn`.
1. **The Container Trap:** We initially used a `SubViewportContainer` with "Stretch" enabled. This was a trap. It locked the resolution to the editor window. We had to forcefully disable `Stretch` in the C# code.
2. **The `SubViewport`:** We placed `MapPreview` inside a `SubViewport` set explicitly to 4096x4096. This acts as an offscreen virtual monitor that doesn't care about the physical screen size.
3. **The `MapDrawProxy`:** We realized that `Texture.GetImage()` only grabs the base pixels, completely ignoring the colored roads and towns drawn by `_Draw()`. We had to dynamically instantiate a `Control` proxy node to stamp the roads onto the virtual monitor *before* taking the picture.
4. **The Flash Timing:** Generating a 4096 map takes time. We had to implement `await ToSignal(GetTree(), "process_frame");` to let Godot unlock the scene tree, and `await ToSignal(RenderingServer... FramePostDraw)` to force the camera to wait until the GPU physically finished painting the roads before snapping the photo.
---
## 🚀 How to Generate a New World
1. Open `MapCaptureTool.tscn` in the Godot Editor.
2. Ensure you do **not** click the main Play button.
3. Press **F6** (Play Current Scene).
4. The editor will freeze for 10-30 seconds while the `ExportMapData` function writes the binary `.dat` file.
5. Once the console prints the success message, check your `user://` folder for the massive, full-resolution `.png` and the `.dat` blueprint.
# /Tools/Scenes — developer environments
Standalone scenes used to run the offline generation scripts. **Never add these to a game export.**
## `MapPreview.tscn`
The 2D map generator itself.
- **Root:** `TextureRect` · **Script:** `MapGenerator.cs`
- Runs the noise maths, builds the heightmap and biome map, plots the A\* road network, writes the
`.dat`, and draws the map via `_Draw()`.
⚠ **This is the project's main scene** (`project.godot` → `run/main_scene`). That means **pressing
F5 anywhere in the project runs this**, regenerating the world and overwriting your `.dat` — it does
not start the game. To view the 3D world, open `Scenes/Main.tscn` and press **F6** instead.
## `MapCaptureTool.tscn`
*(Lives in `/Scenes`, wraps this directory's scene.)* A `SubViewportContainer` → `SubViewport`
(4096×4096) → `MapPreview`. It exists purely to render the map offscreen at full resolution: Godot's
UI layout engine would otherwise scale a 4096-pixel render down to the editor window, producing a
tiny or black PNG.
Note the generator writes the `.dat` on its own — the capture wrapper only matters for the
full-resolution image.
## Generating a new world
1. Open `MapPreview.tscn` (or `Scenes/MapCaptureTool.tscn` for the full-resolution PNG).
2. Press **F6** — *Play Current Scene*.
3. **Expect minutes, not seconds**, and expect the editor to be unresponsive. The A\* road stage is
the slow part and can stall long enough to be worth abandoning; watch the console for
`[A*] 1/4 … 4/4` progress. See `/Tools/Scripts/README.md`.
4. On success the console prints the export path. Files land in `user://` —
`~/.local/share/godot/app_userdata/islaApocolypse/`.
**Then update `ServerConfig.json`'s `WorldSeed`** to match the new `.dat`, or the 3D scene will fail
to load it.

View file

@ -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.
---

View file

@ -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.