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,19 +1,29 @@
|
|||
# Client Module - IslaApocalypse
|
||||
|
||||
**Phase 2 Status:** Active (Mesh Rendering & Vertex Painting Online)
|
||||
|
||||
## Overview
|
||||
The `Client` directory handles the visual representation of the 3D Voxel Engine. It is strictly responsible for receiving pre-calculated mathematical data from the `Server` and `Core` modules and translating it into Godot-native visual nodes (`MeshInstance3D`). It does not calculate collisions, densities, or terrain generation.
|
||||
|
||||
## Key Architecture & Components
|
||||
|
||||
### 1. The Visualizer (`ChunkRenderer.cs`)
|
||||
A script attached to a `MeshInstance3D` node that physically draws a single 32x32 chunk of the world.
|
||||
* **Mesh Generation:** Calls `MarchingCubes.GenerateMesh()` from the `Core` module, passing in the `Densities` and `BlockIDs` scalar fields.
|
||||
* **Vertex Painting:** Dynamically creates a `StandardMaterial3D` and enables `VertexColorUseAsAlbedo = true`. This tells Godot to ignore standard texture maps and instead color the mesh using the exact RGB values we assigned to the vertices based on their `BlockID` (e.g., Green for Grass, Brown for Wasteland).
|
||||
* **World Positioning:** Multiplies the `ChunkPosition` (e.g., [1, 0]) by `Constants.CHUNK_SIZE` and `Constants.VOXEL_SCALE` (1.0f) to perfectly align the chunk in the global 3D space.
|
||||
* **Backface Rendering:** `CullMode` is explicitly disabled to ensure players don't see through the bottom of the map if they clip inside a mountain.
|
||||
|
||||
## Next Immediate Steps (Phase 2, Step 4)
|
||||
* Currently, the renderer draws the exact topography. Once the `Server` implements **Road Carving**, the `Client` will automatically inherit those flattened vertices and paint them with the `ASPHALT` vertex color without needing any code changes here.
|
||||
* Future implementations will include reading `BlockIDs` to paint different UV maps/textures instead of just raw RGB vertex colors.
|
||||
# Client Module
|
||||
|
||||
The visual layer. Takes finished chunk data and turns it into Godot nodes. It calculates nothing —
|
||||
no densities, no terrain, no collision.
|
||||
|
||||
## `ChunkRenderer.cs`
|
||||
|
||||
A `MeshInstance3D` created per chunk by the server, which then calls `RenderChunk(data)`.
|
||||
|
||||
- **Mesh generation.** Calls `MarchingCubes.GenerateMesh()`, passing the density field, the block
|
||||
IDs, and the per-column data the mesher needs to colour correctly: the true (unrounded) surface
|
||||
heights, the biome per column, and the road surface material per column.
|
||||
- **Vertex colouring.** Creates a `StandardMaterial3D` with `VertexColorUseAsAlbedo = true`, so Godot
|
||||
renders the per-vertex colours the mesher assigned rather than a texture. Colours fade between
|
||||
materials across a tunable band instead of switching at whole-metre steps.
|
||||
- **World positioning.** `ChunkPosition × CHUNK_SIZE × VOXEL_SCALE` on X and Z, `y = 0` — chunks are
|
||||
placed by their footprint and carry their full height internally.
|
||||
- **Backface rendering.** `CullMode` is disabled, so the world is still visible from underneath or
|
||||
from inside terrain.
|
||||
|
||||
## Notes
|
||||
|
||||
- **One material instance per chunk.** Each renderer builds its own `StandardMaterial3D`. Since they
|
||||
are all identical, a single shared material would do — an easy win whenever performance work starts.
|
||||
- Chunk positioning is relative to this node's parent, so **moving the `World` node in the scene
|
||||
moves the entire rendered world** with it.
|
||||
|
||||
## Not here yet
|
||||
No textures or UV mapping (raw vertex colour only), no LOD, no player, no UI, no input handling.
|
||||
|
|
|
|||
|
|
@ -1,27 +1,57 @@
|
|||
# Core Module - IslaApocalypse
|
||||
|
||||
**Phase 2 Status:** Active (Voxel Math & Parsing Online)
|
||||
|
||||
## Overview
|
||||
The `Core` directory contains the mathematical foundation, data structures, and parser required to bridge the 2D procedural generation with the 3D Voxel Engine. It is strictly logic-driven and contains no Godot Nodes or visual elements.
|
||||
|
||||
## Key Architecture & Components
|
||||
|
||||
### 1. The Data Bridge (`MapDataParser.cs`)
|
||||
Responsible for deserializing the highly compressed binary `.dat` file generated by the `/Tools` pipeline.
|
||||
* **Outputs:** A `WorldBlueprint` object held in RAM.
|
||||
* **Capabilities:** Reads the 2D heightmap, biome map, and town locations. Crucially, it parses all four tiers of A* road vectors (Highways, Branch Roads, Rugged Roads, Trails) for the Server to use in terrain flattening.
|
||||
|
||||
### 2. Voxel Data Containers (`ChunkData.cs` & `Constants.cs`)
|
||||
* **Chunk Dimensions:** Defined in `Constants.cs`. Currently optimized to `32x32` horizontal with a massive `256` vertical height limit to allow for true AAA-scale mountain ranges without heightmap compression.
|
||||
* **Seamless Borders:** `ChunkData.cs` expands its scalar field arrays (`Densities` and `BlockIDs`) by `+1` on all axes. This allows the Marching Cubes algorithm to sample the neighboring chunk's data, ensuring meshes connect perfectly without gaps.
|
||||
|
||||
### 3. The Math Engine (`MarchingCubes.cs`)
|
||||
Transforms the raw `ChunkData` scalar fields into physical Godot `ArrayMesh` geometry.
|
||||
* **Analytical Normals:** Instead of flat shading, the algorithm calculates exact 3D slope gradients at the corners of each voxel. This produces smooth, realistic lighting across curved terrain.
|
||||
* **Vertex Painting:** Reads the `BlockID` assigned to each voxel corner and applies physical RGB colors directly to the mesh vertices before committing the geometry.
|
||||
|
||||
### 4. Biome & Material Mapping (`BiomePalette.cs`, `BlockRegistry.cs`)
|
||||
Translates the 2D world into physical 3D materials.
|
||||
* **BlockRegistry:** A byte-based lookup table defining physical materials (`SAND`, `STONE`, `WASTELAND_DIRT`, `ASPHALT`).
|
||||
* **BiomePalette Logic:** Uses the 2D `Biome` pixel combined with the 3D `currentY` depth to determine the block type. For example, `Biome.Wasteland` combined with a depth of 0 yields `WASTELAND_DIRT`, while a depth > 4 yields `STONE`.
|
||||
# Core Module
|
||||
|
||||
Shared, stateless logic used by both the server and client paths: the `.dat` parser, the mesher, the
|
||||
voxel data containers, and the material lookups. **No Godot nodes, no scene state.** These scripts
|
||||
define what things are and how to calculate them; they never remember what is currently happening.
|
||||
|
||||
## Components
|
||||
|
||||
### `MapDataParser.cs` — the data bridge
|
||||
Deserializes the binary `.dat` blueprint written by `/Tools` into a `WorldBlueprint` held in RAM:
|
||||
map size, the float heightmap, the biome map, town locations, and **all four tiers** of A\* road
|
||||
vectors (Highways, Branch Roads, Rugged Roads, Trails).
|
||||
|
||||
Read order is fixed and must match the writer exactly: magic string `"ISLA_V1"` → map size →
|
||||
per-pixel `{height float, biome int}` in x-major order → towns → the four road tiers in order.
|
||||
|
||||
⚠ **Wire-format hazard.** Biome and town-tier enums are serialized as their **ordinal values**, with
|
||||
no version gate and no range validation on read. **Never reorder or insert members** in `Enums.cs` —
|
||||
append only, at the end. Reordering silently reinterprets every pixel of every existing `.dat`.
|
||||
(`RoadTier` is exempt: road tiers are stored in separate file sections, so that enum never hits disk.)
|
||||
|
||||
### `ChunkData.cs` + `Constants.cs` — voxel containers and tuning
|
||||
- **Chunk dimensions:** `24 × 24` horizontal, `256` vertical (`Constants.cs`).
|
||||
- **The `+1` padding is structural.** `Densities` and `BlockIDs` are one cell larger on every axis —
|
||||
`[25, 257, 25]` — so the mesher can evaluate the boundary cells shared with the neighbouring chunk
|
||||
and the meshes meet without gaps.
|
||||
- **Per-column data for rendering:** `SurfaceHeights` (the true, unrounded surface), `ColumnBiomes`,
|
||||
and `ColumnRoadMaterial` (0 = not a road). These let the mesher colour by real height rather than a
|
||||
rounded integer.
|
||||
- **Tunables in `Constants.cs`:** `BLEND_BAND_METERS` (how far one surface material fades into the
|
||||
next) and the per-tier road block — width, shoulder, grade-smoothing and surface material for each
|
||||
of the four road tiers, plus the derived cull padding.
|
||||
|
||||
### `MarchingCubes.cs` — the mesher
|
||||
Turns a chunk's density field into a Godot `ArrayMesh`.
|
||||
- **Analytical normals:** exact density gradients at each cell corner, interpolated along the edge by
|
||||
the same fraction used for the vertex position — smooth lighting without Godot's normal pass.
|
||||
- **Deterministic vertex welding:** shared vertices are keyed by an integer `EdgeKey` ordered
|
||||
lowest-to-highest, so neighbouring chunks compute identical keys and no float drift creeps in.
|
||||
- **Vertex colouring:** each vertex is coloured from its true float depth below the surface, fading
|
||||
between the two materials either side of a boundary rather than switching at an integer depth.
|
||||
|
||||
**Density sign convention (load-bearing):** density is **positive above** the surface and **negative
|
||||
below** it. A corner counts as inside the terrain when `density < ISO_LEVEL`.
|
||||
|
||||
### `BiomePalette.cs` + `BlockRegistry.cs` + `BlockData.cs` — materials
|
||||
- **`BlockRegistry`:** byte-ID lookup for every block (`AIR`, `BEDROCK`, `STONE`, `DIRT`, `SAND`, the
|
||||
three grasses, `SNOW`, `WASTELAND_DIRT`, `ASPHALT`).
|
||||
- **`BiomePalette`** answers "what material is here?" twice, deliberately:
|
||||
- `GetVoxelID(...)` — the authoritative **integer** classification by whole-block depth. Decides
|
||||
what is actually stored in each voxel; used for everything non-visual.
|
||||
- `GetBlendedVoxelIDs(...)` — the **rendering** version. Same question by *float* depth, returning
|
||||
the two materials either side of the nearest boundary plus how far between them the point is, so
|
||||
the renderer fades instead of snapping.
|
||||
|
||||
Both take a road-surface byte, so a trail is surfaced in dirt where a highway is surfaced in
|
||||
asphalt.
|
||||
|
|
|
|||
|
|
@ -13,16 +13,26 @@ Based on the answer, it draws a specific set of triangles *through* the invisibl
|
|||
|
||||
### 1. Density (The "Float" Value)
|
||||
In smooth voxels, a point in space isn't just "Solid" (1) or "Empty" (0). It has a continuous **Density** value.
|
||||
* ` 1.0` = Deep underground (Solid Rock).
|
||||
* ` 0.5` = Slightly underground (Dirt).
|
||||
|
||||
⚠ **Mind the sign — this project's convention is the opposite of many tutorials.** Density here is
|
||||
essentially *"how far above the surface am I?"*, computed as `(y − surfaceY)` normalised by the local
|
||||
slope. So it counts **upward**, not downward:
|
||||
|
||||
* ` 1.0` = High in the sky (Empty Space).
|
||||
* ` 0.5` = Slightly above ground (Air).
|
||||
* ` 0.0` = The exact surface of the ground.
|
||||
* `-0.5` = Slightly above ground (Air).
|
||||
* `-1.0` = High in the sky (Empty Space).
|
||||
* `-0.5` = Slightly underground (Dirt).
|
||||
* `-1.0` = Deep underground (Solid Rock).
|
||||
|
||||
### 2. The Iso-Level (The Threshold)
|
||||
The Iso-Level is the exact density value where the "skin" of the world is drawn. Usually, this is `0.0`.
|
||||
* If a corner's density is **greater** than `0.0`, it is "Inside" the terrain.
|
||||
* If a corner's density is **less** than `0.0`, it is "Outside" in the air.
|
||||
The Iso-Level is the exact density value where the "skin" of the world is drawn. Here it is `0.0`
|
||||
(`Constants.ISO_LEVEL`).
|
||||
* If a corner's density is **less** than `0.0`, it is "Inside" the terrain.
|
||||
* If a corner's density is **greater** than `0.0`, it is "Outside" in the air.
|
||||
|
||||
This matches the code: `MarchingCubes.GenerateMesh` sets a corner's bit when
|
||||
`cornerDensities[i] < isolevel`. Getting this backwards inverts every surface normal and makes the
|
||||
world render inside-out — which is a real bug this project has hit before.
|
||||
|
||||
### 3. The Triangulation Table (The Magic Array)
|
||||
A cube has 8 corners. Each corner can either be Inside or Outside.
|
||||
|
|
|
|||
|
|
@ -1,46 +1,50 @@
|
|||
# 📜 Core Scripts Directory - Isla Apocalypse
|
||||
|
||||
## Overview
|
||||
The `/Core/Scripts` directory is the dedicated code repository for all pure C# data structures, universal enumerations, and static mathematical utilities. Everything in this folder is compiled into the shared assembly used by both the authoritative `/Server` and the rendering `/Client`.
|
||||
|
||||
**Core Philosophy: "Pure Data, Zero State."**
|
||||
Scripts in this folder define *what* things are and *how* to calculate them, but they never remember *current* game events. They do not track who is online, what chunks are loaded, or what time of day it is. They are stateless, universal blueprints.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Current Systems (Phase 2)
|
||||
|
||||
### 1. The Voxel Palette System
|
||||
* **`BlockData.cs`**: The fundamental `struct` defining the properties of a single voxel (ID, Name, IsSolid, BaseColor).
|
||||
* **`BlockRegistry.cs`**: The static master dictionary. Contains the hardcoded IDs for every block in the game (Air, Bedrock, Dirt, Asphalt) and provides a safe lookup method (`GetBlock`) for both the mesher and the physics engine.
|
||||
* **`BiomePalette.cs`**: The translation layer between 2D and 3D. Contains the logic that dictates the vertical stacking of blocks based on biome and depth (e.g., ensuring mountains have stone beneath snow, and roads are topped with asphalt).
|
||||
|
||||
### 2. Universal Identifiers
|
||||
* **`Enums.cs`**: The master repository for global enums (`Biome`, `TownTier`, `MapHalf`). By keeping these here, the offline Map Generator, the Server, and the Client are guaranteed to use the exact same integer values for biomes and POIs.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Future Roadmap & Planned Additions (Phase 2 & 3)
|
||||
|
||||
As we build the 3D Chunk Manager and multiplayer networking, this folder will expand to include:
|
||||
|
||||
### 3. The Blueprint Parser
|
||||
* **`MapDataParser.cs`** *(Next Step)*: A static utility to open and decode the `MapData_Seed_[X].dat` binary file into usable C# arrays for the Server to ingest.
|
||||
|
||||
### 4. Chunk Data Structures
|
||||
* **`ChunkData.cs`**: The raw 3D array (`byte[,,]`) that holds the voxel IDs for a specific 16x16x64 area.
|
||||
* *Note:* This structure will include the `IsPlayerProtected` boolean flag to support the "Land Claim" delta-backup system, preventing player bases from being wiped out by chunk corruption.
|
||||
|
||||
### 5. Math & Coordinate Utilities
|
||||
* **`VoxelMath.cs`**: Static helper functions for translating massive 3D World Coordinates into local Chunk Coordinates (e.g., finding out which specific chunk file to load when a player walks to X: 5000, Z: -200).
|
||||
|
||||
### 6. Network Packet Definitions
|
||||
* Structs that define the exact byte layout of multiplayer messages (e.g., `PlayerDigPacket`, `ChatPacket`) to ensure precise Server/Client synchronization.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Directory Rules & Best Practices
|
||||
|
||||
1. **No Godot Node Inheritance:** Scripts here should rarely, if ever, inherit from `Node` or `Node3D`. They are pure C# classes, structs, or static utilities.
|
||||
2. **No `_Process` or `_Ready`:** Because these are not attached to active objects in the game world, they do not use Godot's frame-by-frame loop functions.
|
||||
3. **Strictly Independent:** A script in `/Core/Scripts` cannot reference anything in `/Client` or `/Server`. The dependency flows one way: the Client and Server look *in* to the Core; the Core never looks *out*.
|
||||
# /Core/Scripts
|
||||
|
||||
Pure C# data structures, shared enums, and static maths. Compiled into the shared assembly used by
|
||||
both `/Server` and `/Client`.
|
||||
|
||||
**"Pure data, zero state."** These scripts define *what* things are and *how* to calculate them. They
|
||||
never track live game events — who is online, which chunks are loaded, what time it is.
|
||||
|
||||
## What's actually here
|
||||
|
||||
### Voxel materials
|
||||
- **`BlockData.cs`** — struct describing one block type (ID, name, IsSolid, BaseColor).
|
||||
- **`BlockRegistry.cs`** — the byte-ID master list (`AIR` 0, `BEDROCK`, `STONE`, `DIRT`, `SAND`, the
|
||||
three grasses, `SNOW`, `WASTELAND_DIRT`, `ASPHALT`) with a safe `GetBlock` lookup.
|
||||
- **`BiomePalette.cs`** — decides which material sits where, given biome, depth, and whether the
|
||||
column is roadbed. Two paths on purpose: an **integer** classification that decides what is stored
|
||||
in each voxel, and a **float-depth** version used for rendering that returns the two materials
|
||||
either side of a boundary so colours fade rather than snap.
|
||||
|
||||
⚠ Note that `BlockRegistry` and the mesher's colour table hold **different RGB values** for some
|
||||
blocks. The mesher's table is what you actually see; `BlockData.BaseColor` is currently unused by
|
||||
rendering.
|
||||
|
||||
### Shared identifiers
|
||||
- **`Enums.cs`** — `Biome`, `TownTier`, `MapHalf`, `RoadTier`.
|
||||
|
||||
⚠ **`Biome` and `TownTier` are the `.dat` wire format.** They are declared without explicit values,
|
||||
so each member's ordinal *is* the number written to disk, with no version gate and no validation on
|
||||
read. **Append only, at the end — never reorder or insert.** Doing so silently reinterprets every
|
||||
pixel and every settlement in every existing blueprint.
|
||||
`RoadTier` is exempt: road tiers live in separate sections of the file, so it is never serialized.
|
||||
|
||||
### World data
|
||||
- **`MapDataParser.cs`** — decodes the `.dat` blueprint into a `WorldBlueprint` (heightmap, biome map,
|
||||
towns, four road tiers).
|
||||
- **`ChunkData.cs`** — one chunk's density and block-ID fields, `+1` padded on every axis so the
|
||||
mesher can reach into the neighbouring chunk, plus the per-column data the renderer needs.
|
||||
- **`Constants.cs`** — chunk dimensions, `ISO_LEVEL`, `VOXEL_SCALE`, and the visual/road tunables
|
||||
(material blend band; per-tier road width, shoulder, grade smoothing and surface).
|
||||
|
||||
### Maths
|
||||
- **`MarchingCubes.cs`** — density field → `ArrayMesh`, with analytical normals and deterministic
|
||||
integer-keyed vertex welding.
|
||||
- **`MATH_MARCHING_CUBES.md`** — an explainer of the algorithm.
|
||||
|
||||
## Rules
|
||||
1. **No Godot node inheritance.** Pure classes, structs and statics.
|
||||
2. **No `_Process` / `_Ready`.** Nothing here is attached to a live scene object.
|
||||
3. **Dependencies flow inward only.** `/Server` and `/Client` reference `/Core`; `/Core` never
|
||||
references them.
|
||||
|
|
|
|||
|
|
@ -1,49 +1,41 @@
|
|||
# 🗄️ Data Directory - Isla Apocalypse
|
||||
|
||||
## Overview
|
||||
The `/Data` directory is the static repository for all generated world files, visual previews, and configuration structures. It acts as the handoff point between the offline `/Tools` (which write the data) and the live `/Server` (which reads the data).
|
||||
|
||||
**Core Philosophy: "The Immutable Source of Truth."**
|
||||
Files stored in this primary directory are considered *Base Blueprints*. They are the starting point of the world before any player interacts with it. The Game Client should almost never read from this folder directly; it receives this data via the Server.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Current Contents (Phase 1)
|
||||
|
||||
### 1. Binary Blueprints (`.dat`)
|
||||
* **Format:** Custom serialized binary (`MapData_Seed_[X].dat`).
|
||||
* **Purpose:** Contains the highly compressed, raw mathematical output of the 2D Generator (Map Size, Height floats, Biome IDs, POI coordinates, Highway vectors).
|
||||
* **Usage:** Read by the Server's Chunk Manager at startup to construct the untouched 3D voxel world.
|
||||
|
||||
### 2. Map Previews (`.png`)
|
||||
* **Format:** 1024x1024 RGBA Images (`Map_Seed_[X]_[Time].png`).
|
||||
* **Purpose:** High-resolution visual snapshots of the generated seeds.
|
||||
* **Usage:** Used by the developer/server admin to visually review and select the best island layout before spinning up the 3D server.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Future Roadmap & Planned Additions
|
||||
|
||||
As the game expands, this folder will be subdivided to organize different types of static game data:
|
||||
|
||||
### 3. /Prefabs (Planned - Phase 2/3)
|
||||
* **Format:** `.json` or custom `.prefab` binaries.
|
||||
* **Purpose:** 3D building templates (e.g., `GasStation_Tier3.json`) created by the Prefab Editor. The Server uses these files to spawn structures at the coordinates dictated by the master `.dat` blueprint.
|
||||
|
||||
### 4. /Configs (Planned - Phase 3)
|
||||
* **Format:** `.json` or `.cfg`.
|
||||
* **Purpose:** Human-readable configuration files for game balance.
|
||||
* `LootTables.json`: Defines what items spawn in which containers based on POI Tier.
|
||||
* `VoxelPalette.json`: Maps the 2D Biome IDs to 3D Voxel types.
|
||||
* `SpawnRates.json`: Defines zombie/animal spawn limits and Blood Moon horde scaling.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Directory Rules & Best Practices
|
||||
|
||||
1. **NO Scripts or Code:** This directory must strictly contain data files (`.dat`, `.png`, `.json`, `.csv`). It contains zero executable logic.
|
||||
2. **Live Saves vs. Base Data:** * This folder holds the **Base Game Data**.
|
||||
* *Live Player Saves* and *Terrain Deformation Diff Files* should generally be saved to Godot's safe `user://` path on the host machine, NOT in this project folder. This prevents live server saves from accidentally being bundled into the game's base code.
|
||||
3. **Version Control (Git) Warnings:**
|
||||
* `.dat` and `.png` files can become very large.
|
||||
* **Rule:** Only commit the "Official Release" seed files to your repository. Use a `.gitignore` file to ignore random test generations so you don't bloat your project repository with gigabytes of discarded test maps.
|
||||
# /Data
|
||||
|
||||
Intended handoff point for static world data written by `/Tools` and read by `/Server`.
|
||||
|
||||
## ⚠️ Currently empty
|
||||
|
||||
**This directory holds nothing but this README.** The generator does **not** write here.
|
||||
|
||||
Generated world data goes to Godot's `user://` path instead — outside the project entirely. On Linux
|
||||
that is:
|
||||
|
||||
```
|
||||
~/.local/share/godot/app_userdata/islaApocolypse/
|
||||
MapData_Seed_<seed>.dat the blueprint (~512 MB at 8K)
|
||||
Map_Seed_<seed>.png visual snapshot of the map
|
||||
```
|
||||
|
||||
That is a good arrangement and worth keeping: it means a 512 MB blueprint can never be committed by
|
||||
accident, and regenerating a world never dirties the repo.
|
||||
|
||||
## The blueprint format, for reference
|
||||
|
||||
`MapData_Seed_<seed>.dat` is custom binary, written by `MapGenerator.ExportMapData` and read by
|
||||
`Core/Scripts/MapDataParser.cs`. Order is fixed and the two sides must match exactly:
|
||||
|
||||
1. `"ISLA_V1"` — length-prefixed magic string
|
||||
2. map size (int32)
|
||||
3. for every pixel, x-major: height (float32) + biome (int32)
|
||||
4. town count, then per town: x, y (float32), tier (int32)
|
||||
5. the four road tiers in order — Highway, Branch, Rugged, Trail — each as a path count, then per
|
||||
path a point count and its x/y float pairs
|
||||
|
||||
**Enum ordinals are the serialized values** and there is no version gate beyond the magic string and
|
||||
no range validation on read. See the warning in `Core/Scripts/README.md` before touching `Enums.cs`.
|
||||
|
||||
## If this folder ever does hold data
|
||||
|
||||
- **Data files only** — no scripts, no logic.
|
||||
- **Keep large generated `.dat`/`.png` files out of git.** Commit only a deliberately chosen release
|
||||
seed, if any.
|
||||
- Live player saves and terrain edits belong in `user://`, never in the project folder.
|
||||
|
|
|
|||
124
README.md
124
README.md
|
|
@ -1,28 +1,108 @@
|
|||
# IslaApocalypse - Voxel Engine Architecture
|
||||
# IslaApocalypse
|
||||
|
||||
**Current Version:** v0.0.1 (Phase 2 - Voxel Engine Online, v0.0.x Prototyping / Tech Demo)
|
||||
**Engine:** Godot 4 (C#)
|
||||
**Version:** v0.0.1 — prototyping / salvage. Not a playable build.
|
||||
**Engine:** Godot **4.7.1** · C# / .NET 8 (`Godot.NET.Sdk 4.7.1`)
|
||||
|
||||
## Project Overview
|
||||
IslaApocalypse is a procedurally generated, multiplayer-ready survival/driving game. The engine uses a two-phase generation system: first building a massive 4096x4096 2D topographical blueprint, and then dynamically translating that data into a 3D Marching Cubes voxel world at runtime.
|
||||
A procedurally generated, multiplayer-ready voxel survival game on a post-nuclear Caribbean island.
|
||||
Terrain is smooth (Marching Cubes), not blocky.
|
||||
|
||||
## Development State
|
||||
* **Phase 1: 2D Blueprint Engine** -> **[COMPLETE]**
|
||||
* **Phase 2: 3D Voxel Engine** -> **[IN PROGRESS - Basic Rendering Online]**
|
||||
> **Design intent, decisions and rationale live in the design vault, not here.** This README and the
|
||||
> per-directory ones describe **what the code does**. For *why*, see the vault repo
|
||||
> (`islaApocalypse-vault-v0.1`).
|
||||
|
||||
### Current Capabilities (What works right now):
|
||||
1. **The 2D Blueprint (`MapGenerator.cs`):** Generates a 4096x4096 map using `FastNoiseLite`. It features dynamic sea levels, a massive impact crater, tiered city placements (Capitol, Hubs, Villages), and a heavily optimized A* pathfinding network (Highways, Branch Roads, Trails) that utilizes Chaikin's smoothing algorithm.
|
||||
2. **Binary Serialization:** Exports the entire 16-million pixel array and path vectors into a lightweight, byte-aligned `.dat` file.
|
||||
3. **The Data Bridge (`MapDataParser.cs`):** Seamlessly deserializes the `.dat` file back into RAM as a `WorldBlueprint` for the server to read.
|
||||
4. **Authoritative Chunk Management (`ServerChunkManager.cs`):** Dynamically locates the Capitol City, converts pixel coordinates to 3D chunk coordinates, and generates a grid of `ChunkData` objects (32x32x256 meters) around the player.
|
||||
5. **Marching Cubes Rendering (`MarchingCubes.cs`):** Translates 2D heightmaps into 3D geometry. Features analytical normals for smooth lighting and dynamically paints Vertex Colors based on the 2D `BiomeMap` (Wasteland, Sand, Grass, Stone).
|
||||
---
|
||||
|
||||
## Directory Architecture
|
||||
* `/Tools/`: Contains the v1.0 2D Map Generator and preview scenes. Run `MapCaptureTool.tscn` to generate a new world seed.
|
||||
* `/Core/`: The math and data foundation. Contains the Binary Parser, Marching Cubes algorithm, Biome Palettes, and `ChunkData` structs.
|
||||
* `/Server/`: The Authoritative Server logic. Manages chunk loading, calculates voxel densities, and handles chunk culling.
|
||||
* `/Client/`: The visual layer. Takes raw `ChunkData` and translates it into Godot `MeshInstance3D` objects with vertex-colored materials.
|
||||
## How the world gets built
|
||||
|
||||
## Next Immediate Steps (Phase 2, Step 4)
|
||||
* **Road Carving:** Inject A* road vector data into the `ServerChunkManager` to override the natural heightmap, physically flattening the 3D terrain and painting Asphalt blocks to create drivable highways through the mountains.
|
||||
* **Chunk Seams:** Implement normal-blending across chunk borders to remove grid-line lighting artifacts.
|
||||
Two phases, with a file in between.
|
||||
|
||||
1. **2D blueprint** (`Tools/Scripts/MapGenerator.cs`) — FastNoiseLite topography, dynamic sea level,
|
||||
an impact crater, biome zoning, tiered town placement, and an A\* road network in four tiers
|
||||
(Highway, Branch, Rugged, Trail). Written to a binary `.dat`.
|
||||
2. **3D voxel world** (`Server/` + `Core/`) — the `.dat` is parsed into RAM, and chunks are built
|
||||
around the Capitol: a density field per chunk, meshed with Marching Cubes, vertex-coloured by
|
||||
biome and depth, with roads carved into the terrain.
|
||||
|
||||
**Map size is config-driven**, not fixed. The shipped `ServerConfig.json` selects the `8K` profile →
|
||||
**8192 × 8192**, where 1 pixel = 1 metre = 1 voxel footprint.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ How to actually run it
|
||||
|
||||
**Pressing Play (F5) does NOT run the game.** The project's main scene is the 2D map generator, so F5
|
||||
regenerates the entire world (minutes — and it currently stalls in the A\* road pass) and overwrites
|
||||
your `.dat`.
|
||||
|
||||
**To view the 3D world:**
|
||||
1. Open `Scenes/Main.tscn`.
|
||||
2. Press **F6** — *Run Current Scene*.
|
||||
|
||||
It reads `ServerConfig.json`, loads the existing `.dat`, and builds the chunk grid.
|
||||
|
||||
**To generate a new world** (only when you actually want a new map): press **F5**, or open
|
||||
`Tools/Scenes/MapPreview.tscn` and press F6.
|
||||
|
||||
### Before you run it — set `ChunkRadius`
|
||||
|
||||
`ServerConfig.json`, at the project root:
|
||||
|
||||
```json
|
||||
{ "WorldSeed": 1063685222, "MapProfile": "8K", "TownDensity": "Normal", "ChunkRadius": 32 }
|
||||
```
|
||||
|
||||
`ChunkRadius` is a **load radius in chunks**, not a chunk size. The grid built at boot is
|
||||
`(2 × radius)²` chunks, all synchronously:
|
||||
|
||||
| ChunkRadius | Chunks built | Cost |
|
||||
|---|---|---|
|
||||
| 4 | 64 | loads in seconds |
|
||||
| 8 | 256 | still quick |
|
||||
| 32 (shipped) | 4,096 | ~3.6 GB, minutes |
|
||||
|
||||
**Use 4–8 while iterating.** 32 is for looking at a lot of world at once.
|
||||
|
||||
`MapProfile` accepts `4K` / `6K` / `8K` / `10K` → 4096 / 6144 / 8192 / 10240.
|
||||
|
||||
### Where the generated world lives
|
||||
|
||||
Outputs go to Godot's `user://`, **not** into this repo — on Linux,
|
||||
`~/.local/share/godot/app_userdata/islaApocolypse/`:
|
||||
- `MapData_Seed_<seed>.dat` — the blueprint (~512 MB at 8K)
|
||||
- `Map_Seed_<seed>.png` — a visual snapshot of the map, for reviewing and picking seeds
|
||||
|
||||
**`WorldSeed` must match an existing `.dat`**, or the load fails with
|
||||
`CRITICAL ERROR: Map file not found` and you get an empty scene.
|
||||
|
||||
---
|
||||
|
||||
## Directory layout
|
||||
|
||||
| Path | What's in it |
|
||||
|---|---|
|
||||
| `Core/` | Shared, stateless logic: the `.dat` parser, Marching Cubes, chunk data, block registry, biome palette, constants. Used by both the server and client paths. |
|
||||
| `Server/` | Authoritative world building: loads the blueprint, builds chunks around the Capitol, computes densities, carves roads. |
|
||||
| `Client/` | Rendering: turns finished chunk data into `MeshInstance3D` geometry with a vertex-coloured material. |
|
||||
| `Tools/` | Offline developer tooling — the 2D map generator and its scenes. Never shipped. |
|
||||
| `Scenes/` | Runtime scenes. `Main.tscn` is the 3D world. |
|
||||
| `Data/` | Handoff folder for static world data. Currently documentation only. |
|
||||
| `Resources/` | Intended home for Godot `.tres` asset definitions. Currently documentation only. |
|
||||
|
||||
---
|
||||
|
||||
## Current state
|
||||
|
||||
**Working:** 2D generation end to end at 8K · `.dat` write and read · chunk building · Marching Cubes
|
||||
meshing with analytical normals and seam-free integer vertex welding · road carving for **all four
|
||||
tiers** with per-tier width and grade · biome/depth vertex colouring with soft material fades.
|
||||
|
||||
**Known issues:**
|
||||
- **A\* road generation is slow enough to stall a full regeneration** — a 67-million-node grid at
|
||||
1 px granularity, with a same-sized setup loop. The dominant open problem.
|
||||
- **Faint seam lines along chunk borders** — a normals/shading difference between independently
|
||||
meshed chunks, not a gap in the geometry.
|
||||
- **No player, no collision, no water, and no camera controller** — there is no input handling in the
|
||||
codebase at all. Inspect the world with the editor camera.
|
||||
- The world is built once at boot: **no chunk streaming or unloading** yet.
|
||||
- Two road issues remain: roadbed elevation can jump where two separate stretches of road pass close
|
||||
together, and road *materials* are only a coarse asphalt/dirt split.
|
||||
|
|
|
|||
|
|
@ -1,49 +1,24 @@
|
|||
# 📦 Resources Directory - Isla Apocalypse
|
||||
|
||||
## Overview
|
||||
The `/Resources` directory acts as the game's central library for all static assets and Godot-specific data containers (primarily `.tres` files, 3D models, textures, and audio).
|
||||
|
||||
**Core Philosophy: "The Reusable Building Blocks."**
|
||||
If the Server is the brain and the Client is the eyes, Resources are the memories. They define the *properties* of things in the world. If there are 50 zombies on screen, you don't want 50 copies of their texture and max health data in your RAM. Instead, all 50 zombies reference a single `ZombieBase.tres` resource.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Core Systems (Phase 2 & 3)
|
||||
|
||||
### 1. Voxel & Block Definitions
|
||||
* **Format:** Custom `.tres` files based on a `BlockData` C# script (located in `/Core`).
|
||||
* **Function:** Defines the properties of every voxel in the game.
|
||||
* **Examples:** `Dirt.tres` (Texture: brown_dirt.png, Durability: 100, StepSound: dirt_crunch.ogg), `Asphalt.tres` (Texture: road.png, Durability: 500, StepSound: hard_step.ogg). Both the Client and Server read these to know how a block looks and behaves.
|
||||
|
||||
### 2. Item & Inventory Data
|
||||
* **Format:** Custom `.tres` files for `ItemData`.
|
||||
* **Function:** Defines every item a player can hold, craft, or drop.
|
||||
* **Examples:** `StoneAxe.tres` (Icon: axe.png, Damage: 15, BlockDamage: 40, MaxStack: 1). The Server uses this to calculate damage; the Client uses this to draw the icon in your hotbar.
|
||||
|
||||
### 3. Audio & Visual Assets
|
||||
* **Materials & Shaders:** The `.material` and `.gdshader` files used by the Client's chunk mesher (e.g., `TerrainMaterial.tres`).
|
||||
* **3D Models:** The `.glb` or `.gltf` files for weapons, dropped items, and entities.
|
||||
* **Audio Streams:** The `.wav` or `.ogg` files for ambient wind, UI clicks, and zombie attacks.
|
||||
|
||||
### 4. UI Themes & Fonts
|
||||
* Godot `Theme` resources that dictate the colors, fonts, and border styles of the entire user interface, ensuring the inventory menus match the main menu.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Directory Organization Strategy
|
||||
|
||||
To prevent this folder from turning into a massive junk drawer, it must be strictly subdivided:
|
||||
|
||||
* `/Resources/Blocks/`
|
||||
* `/Resources/Items/`
|
||||
* `/Resources/Models/`
|
||||
* `/Resources/Audio/`
|
||||
* `/Resources/UI/`
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Directory Rules & Best Practices
|
||||
|
||||
1. **Text Over Binary:** Always save custom Godot resources as `.tres` (Text Resource) rather than `.res` (Binary Resource). Text resources can be read by version control (Git), allowing you to see exactly when someone changed the damage of a Stone Axe from 15 to 20.
|
||||
2. **Stateless Data Only:** A Resource should never track live game state. For example, `Pistol.tres` holds the *Max Ammo* capacity (15), but it should NEVER hold the *Current Ammo* (7). Current ammo is a live state tracked by the Server.
|
||||
3. **Shared Access:** Because Resources are just data, they are completely safe to be referenced by both the `/Server` and the `/Client`.
|
||||
# /Resources
|
||||
|
||||
Intended home for Godot `.tres` asset definitions and static assets — block properties, item data,
|
||||
materials, models, audio, UI themes.
|
||||
|
||||
## ⚠️ Currently empty
|
||||
|
||||
**This directory holds nothing but this README.** No resources exist yet.
|
||||
|
||||
Block properties currently live **in code**, not in resources: `Core/Scripts/BlockRegistry.cs` builds
|
||||
its dictionary of `BlockData` (ID, name, IsSolid, colour) in a static constructor. Terrain rendering
|
||||
uses a `StandardMaterial3D` created at runtime per chunk in `ChunkRenderer.cs`, not a saved material.
|
||||
|
||||
Moving that data into `.tres` files is a reasonable future step — it would make block definitions
|
||||
editable without recompiling and diffable in git — but nothing depends on it today.
|
||||
|
||||
## Conventions, if and when it fills up
|
||||
|
||||
1. **`.tres`, not `.res`.** Text resources are readable in a diff; binary ones are not.
|
||||
2. **Stateless only.** A resource holds a weapon's *max* ammo, never its *current* ammo. Live state
|
||||
belongs to the server.
|
||||
3. **Subdivide early** — `Blocks/`, `Items/`, `Models/`, `Audio/`, `UI/` — before it becomes a junk
|
||||
drawer.
|
||||
4. Resources are plain data, so both `/Server` and `/Client` can safely reference them.
|
||||
|
|
|
|||
|
|
@ -1,37 +1,46 @@
|
|||
# 🌍 /Scenes - The Playable Game
|
||||
|
||||
## Overview
|
||||
This directory contains the core runtime scenes for *Isla Apocalypse*. Unlike the `/Tools` directory, the scenes here are exactly what the end-user (or the Dedicated Server) will run.
|
||||
|
||||
**Core Philosophy:** These scenes do **not** generate the world from scratch. They strictly load and interpret the immutable `MapData.dat` blueprint provided by the developers. This ensures lightning-fast server boot times and complete parity between the server and the clients.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Core Scenes
|
||||
|
||||
### `Main.tscn` (The Entry Point)
|
||||
**Status:** In Transition (Prepping for 1:1 Scale Ingestion)
|
||||
|
||||
This is the master root scene. Currently, it acts as the Dedicated Server environment, responsible for reading the 2D blueprint and translating it into a physical 3D voxel world using the `ServerChunkManager`.
|
||||
|
||||
#### ⚔️ The Great 4096 Struggle (The 3D Ramifications)
|
||||
Our decision to upgrade the master blueprint from 1024x1024 to a massive 4096x4096 (1:1 scale) fundamentally changed how `Main.tscn` must operate.
|
||||
|
||||
While the 2D generator struggled with math and UI layouts, the 3D server must now deal with **Memory Management**.
|
||||
* **The Scale Shift:** In the old 1024 version, 1 data pixel equaled 4 meters of 3D space. Now, 1 pixel = 1 meter. This perfectly accommodates human-scale base building (like *7 Days to Die*), but it means the total data footprint of the world is 16 times larger.
|
||||
* **The Chunking Mandate:** `Main.tscn` can no longer afford to load the entire map into RAM at startup. The `ServerChunkManager` must operate strictly on a localized, dynamic grid—only loading the 1-meter chunks immediately surrounding active players.
|
||||
|
||||
#### 🛡️ The Arsenal is Ready
|
||||
Despite the massive scale increase, `Main.tscn` is structurally prepared for the 4096 blueprint thanks to heavy engine optimizations built during Phase 1:
|
||||
1. **The EdgeKey Welder:** Completely eliminates floating-point drift and mesh seams across the new high-density chunk borders.
|
||||
2. **Analytical Normals:** Bypasses Godot's slow native normal calculation, using mathematical gradients to light the massive 1:1 voxel world instantly.
|
||||
3. **The +1 Border Fix:** Chunk arrays are padded by exactly 1 unit to flawlessly sample neighbor data without requiring expensive cross-chunk blurring.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 The Immediate Roadmap
|
||||
When Phase 2 resumes, `Main.tscn` will undergo the following upgrades to ingest the new 4096 map:
|
||||
|
||||
1. **Re-syncing the Parser:** Uncommenting the Logistical Network logic in `MapDataParser.cs` so the server can read the newly fixed roads and towns.
|
||||
2. **Dynamic Chunk Loading:** Scrapping the hardcoded `10x10` test grid in favor of a proximity-based chunk loader.
|
||||
3. **Terrain Flattening:** Implementing logic for the voxel engine to read the road and town data and automatically flatten the 3D terrain beneath them.
|
||||
# /Scenes — the runtime scenes
|
||||
|
||||
Unlike `/Tools`, these are what actually runs the game. They **do not generate the world** — they
|
||||
load and interpret an existing `.dat` blueprint.
|
||||
|
||||
## `Main.tscn` — the 3D world
|
||||
|
||||
| Node | What it is |
|
||||
|---|---|
|
||||
| `World` (`Node3D`) | Root. Carries `ServerChunkManager.cs` — this is what builds the world. |
|
||||
| `Camera3D` | Child of `World`. The server teleports it above the Capitol at startup. |
|
||||
| `DirectionalLight3D` | Sunlight. |
|
||||
| `WorldEnvironment` | Ambient light. |
|
||||
|
||||
### Running it
|
||||
|
||||
**Open this scene and press F6** (*Run Current Scene*).
|
||||
|
||||
⚠ **Do not press F5.** The project's main scene is the 2D map generator, not this — F5 regenerates
|
||||
the whole world and overwrites your `.dat`.
|
||||
|
||||
At boot the manager reads `ServerConfig.json`, loads `MapData_Seed_<WorldSeed>.dat` from `user://`,
|
||||
finds the Capitol, and builds a `(2 × ChunkRadius)²` grid of chunks around it. **Set `ChunkRadius` to
|
||||
4–8 first** unless you specifically want the full 4,096-chunk, ~3.6 GB boot.
|
||||
|
||||
If the seed in `ServerConfig.json` doesn't match an existing `.dat`, the load fails and you get an
|
||||
empty scene.
|
||||
|
||||
### Two things that will confuse you
|
||||
|
||||
- **The camera cannot be moved at runtime.** There is no camera controller and no input handling
|
||||
anywhere in the codebase. The server overrides whatever transform you save here, placing the camera
|
||||
above the Capitol looking straight down — which is also a degenerate `LookAt`, so its roll is
|
||||
arbitrary and Godot logs a warning. To view from elsewhere you have to edit the teleport code.
|
||||
- **Moving the `World` node moves the entire world.** Chunks are added as its children, so a stray
|
||||
drag in the editor offsets all rendered terrain. If everything looks displaced, check `World`'s
|
||||
transform is zeroed.
|
||||
|
||||
## `MapCaptureTool.tscn`
|
||||
|
||||
A `SubViewportContainer` wrapping `Tools/Scenes/MapPreview.tscn` at 4096×4096. It exists so the map
|
||||
can be rendered offscreen at full resolution regardless of monitor size. Only needed for the PNG
|
||||
snapshot path — `MapPreview.tscn` generates the `.dat` on its own.
|
||||
|
||||
## Not here yet
|
||||
No player scene, no UI, no menu. `Main.tscn` is currently a viewer, not a game.
|
||||
|
|
|
|||
|
|
@ -1,22 +1,52 @@
|
|||
# Server Module - IslaApocalypse
|
||||
|
||||
**Phase 2 Status:** Active (Authoritative Chunk Management Online)
|
||||
|
||||
## Overview
|
||||
The `Server` directory contains the authoritative logic for the 3D Voxel Engine. It acts as the bridge between the static 2D `WorldBlueprint` residing in RAM and the physical 3D environment generated around the player. This architecture ensures that in a future multiplayer environment, the server dictates the terrain and sends chunk data to the clients.
|
||||
|
||||
## Key Architecture & Components
|
||||
|
||||
### 1. The Authoritative Node (`ServerChunkManager.cs`)
|
||||
Attached to the root of the `Main.tscn` world scene, this script manages the lifecycle of the entire 3D environment.
|
||||
* **Initialization:** Upon boot, it reads the `WorldBlueprint` and dynamically locates the exact X/Y pixel coordinates of the `Capitol` city to use as the initial world spawn point.
|
||||
* **Coordinate Translation:** Converts 2D pixel coordinates into 3D chunk grid coordinates (e.g., Map Pixel [2048, 2048] becomes Chunk [64, 64]).
|
||||
* **Memory Management:** Maintains an `_activeChunks` dictionary to track which chunks are currently loaded in RAM, preventing duplicate generation and allowing for future chunk culling/unloading when the player moves away.
|
||||
|
||||
### 2. Terrain Math & Generation
|
||||
* **True Vertical Scaling:** Height calculation directly multiplies the raw `FastNoiseLite` float (0.0 to 1.0) against `Constants.CHUNK_HEIGHT` (256 meters). This avoids heightmap compression and allows for towering, AAA-scale mountain cliffs.
|
||||
* **Density Calculation:** Uses exact surface interpolation to calculate the signed 3D distance of every voxel relative to the surface. This prevents terrain collapsing on horizontal edges and creates mathematically perfect slopes for the Marching Cubes algorithm.
|
||||
* **Biome Injection:** Samples the `BiomeMap` at the exact X/Z world coordinate to assign a specific `BlockID` (via `BiomePalette`) to every voxel in the chunk.
|
||||
|
||||
## Next Immediate Steps (Phase 2, Step 4)
|
||||
* **A* Road Carving:** The Server Chunk Manager needs to be updated to cross-reference the `Highways` and `BranchRoads` vectors from the blueprint. If a chunk contains a road, the server must mathematically flatten the `exactSurfaceY` and override the `BlockID` to `ASPHALT`.
|
||||
# Server Module
|
||||
|
||||
Authoritative world building. Turns the static `WorldBlueprint` in RAM into physical 3D chunks. In a
|
||||
future multiplayer setup this is the side that dictates terrain and ships chunk data to clients.
|
||||
|
||||
## `ServerChunkManager.cs`
|
||||
|
||||
Attached to the `World` root node of `Scenes/Main.tscn`. Runs the whole 3D world at boot.
|
||||
|
||||
### Startup
|
||||
1. Loads `ServerConfig.json` and the seed's `.dat` blueprint.
|
||||
2. **Finds the Capitol** in the parsed town list and uses it as the world origin point.
|
||||
3. Converts its pixel position to chunk coordinates (`pixel / CHUNK_SIZE`).
|
||||
4. Builds a `(2 × ChunkRadius)²` grid of chunks around it — **synchronously, all at boot**.
|
||||
5. Teleports the `Camera3D` to 120 m above the Capitol, looking down.
|
||||
|
||||
⚠ **Two things to know about startup.** The chunk grid is built in one blocking pass with no
|
||||
streaming or unloading, so `ChunkRadius` directly controls boot cost — 32 means 4,096 chunks and
|
||||
roughly 3.6 GB. And the camera `LookAt` points straight down, which is a degenerate case: the up
|
||||
vector ends up parallel to the view direction, so camera roll is undefined and Godot logs a warning.
|
||||
|
||||
### Per-chunk generation
|
||||
- **Road culling first.** Only the road segments whose bounding box reaches this chunk are kept,
|
||||
each tagged with its `RoadTier`. The padding is derived from the widest shoulder any tier has plus
|
||||
a margin, so widening a road cannot silently truncate it at chunk edges.
|
||||
- **Surface height per column** (`GetExactSurface`) — the blueprint height scaled into the chunk's
|
||||
usable vertical band, then modified by any road carving.
|
||||
- **Density per voxel** — `(y − surfaceY)` normalised by the local slope, giving a signed distance to
|
||||
the surface. Positive above, negative below.
|
||||
- **Block IDs per voxel** via `BiomePalette`, plus the per-column data the renderer needs.
|
||||
- Hands the finished chunk to a `ChunkRenderer`.
|
||||
|
||||
### Road carving
|
||||
All four tiers carve, each with its own character (widest and smoothest for highways, narrow and
|
||||
terrain-hugging for trails — values in `Constants.cs`).
|
||||
|
||||
For each column, the carve finds **the nearest road whose shoulder actually reaches it** — not simply
|
||||
the nearest road, since tiers have different reach and a nearby footpath must not shadow a highway
|
||||
still covering the column. It then reads the roadbed height at the closest point *along* that
|
||||
segment, blending between a straight ramp between the segment's endpoints ("holds a grade") and the
|
||||
terrain directly beneath ("hugs the land") according to the tier.
|
||||
|
||||
Inside the road radius the column is flattened to that height and flagged with the tier's surface
|
||||
material; out to the shoulder radius it eases back to natural ground with a smoothstep.
|
||||
|
||||
`HeightAtPixel` samples the heightmap **bilinearly** — road path points are fractional, and nearest-cell
|
||||
sampling produced a metre-scale staircase along the roadbed.
|
||||
|
||||
## Not here yet
|
||||
No chunk streaming or unloading, no collision, no networking, no player. The "server" is currently a
|
||||
node in the same scene as the renderer — the server/client split is structural, not a process
|
||||
boundary.
|
||||
|
|
|
|||
104
Tools/README.md
104
Tools/README.md
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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…
Reference in a new issue