81 lines
4.1 KiB
Markdown
81 lines
4.1 KiB
Markdown
|
|
# BSP Chunk Streaming Design
|
||
|
|
|
||
|
|
Minecraft-style infinite procedural world using BSP geometry. The world is a grid of BSP chunks that generate and stream as the player explores. Both interior (dungeons, courtyards) and exterior (hills, cliffs) terrain use BSP representation.
|
||
|
|
|
||
|
|
## Chunk Addressing
|
||
|
|
|
||
|
|
`ChunkId::Bsp(u32)` becomes `ChunkId::Bsp { cx: i32, cz: i32 }`. Each chunk covers a 16x16 cell region (1024x1024 world units). World-space origin of chunk `(cx, cz)` is `(cx * 1024.0, cz * 1024.0)`.
|
||
|
|
|
||
|
|
The `ChunkMessage` transport header already has `cx/cy/cz` fields (currently unused) — we start populating them. The `id` field becomes `hash(cx, cz)` for fragment assembly deduplication.
|
||
|
|
|
||
|
|
## Procgen — Biome Selection
|
||
|
|
|
||
|
|
The server holds a `world_seed: u64`. For each chunk at `(cx, cz)`:
|
||
|
|
|
||
|
|
1. Sample noise at `(cx * scale, cz * scale)` with the world seed
|
||
|
|
2. Map noise value to biome:
|
||
|
|
- **Dungeon** (noise < -0.2): Indoor rooms with corridors, walls, ceiling. Existing `generate_rooms` logic.
|
||
|
|
- **Courtyard** (noise -0.2 to 0.2): Central open area with wing rooms. Existing `generate_courtyard` logic.
|
||
|
|
- **Exterior** (noise > 0.2): Open terrain with height variation, no ceiling, cliff walls at steep changes.
|
||
|
|
3. Per-chunk seed: `hash(world_seed, cx, cz)` for deterministic RNG.
|
||
|
|
4. All vertex positions emitted in world space: offset by `(cx * 1024.0, cz * 1024.0)`.
|
||
|
|
|
||
|
|
## Procgen — Exterior Terrain
|
||
|
|
|
||
|
|
New `generate_exterior` function:
|
||
|
|
|
||
|
|
- Each cell gets a floor height from fine-grained noise at world-space position
|
||
|
|
- All cells open (no ceiling)
|
||
|
|
- Walls emitted between adjacent cells with height difference > 32 units (cliff faces)
|
||
|
|
- No walls at chunk edges — floor extends to boundary, noise is continuous across chunks
|
||
|
|
- Single directional light (sunlight) instead of per-room point lights
|
||
|
|
- Materials 7/8/9 (ground/cliff/grass)
|
||
|
|
|
||
|
|
## Server Streaming
|
||
|
|
|
||
|
|
Track player's chunk coordinate: `chunk_cx = floor(player.x / 1024)`, `chunk_cz = floor(player.z / 1024)`.
|
||
|
|
|
||
|
|
Each tick, compute 3x3 ring around player vs `ClientChunkState.known`:
|
||
|
|
|
||
|
|
- **New chunks in range**: Generate lazily, queue for streaming
|
||
|
|
- **Chunks leaving range**: No action — client LRU handles eviction
|
||
|
|
- **Active chunk**: The chunk the player stands in. `CHUNK_ENTER` sent when it changes.
|
||
|
|
|
||
|
|
Streaming priority: player's chunk bursts at 64 fragments/tick, neighbors at 8 fragments/tick.
|
||
|
|
|
||
|
|
## Client — Multi-Chunk Rendering & Collision
|
||
|
|
|
||
|
|
**World struct**: Add `loaded_chunks[9]` array for the 3x3 ring. `active_chunk` remains the player's chunk (collision).
|
||
|
|
|
||
|
|
**Sync**: Iterate chunk cache for the 3x3 ring around player's chunk coordinate. Populate `loaded_chunks`.
|
||
|
|
|
||
|
|
**Rendering**: Iterate `loaded_chunks`, call `pxl8_bsp_render` for each. Vertices are in world space — no transform needed. Frustum-cull entire chunks before BSP rendering (chunk AABB: 1024x128x1024).
|
||
|
|
|
||
|
|
**Collision**: `pxl8_sim_trace` checks `active_chunk` BSP. Swap active chunk when player crosses boundary. Cross-chunk collision is a future refinement.
|
||
|
|
|
||
|
|
**BSP render state**: Store `pxl8_bsp_render_state*` inside each `pxl8_world_chunk`, created on arrival, destroyed on eviction.
|
||
|
|
|
||
|
|
## Wire Protocol
|
||
|
|
|
||
|
|
No new message types. Existing messages gain spatial meaning:
|
||
|
|
|
||
|
|
- `ChunkMessage.cx/cz`: populated with grid coordinates
|
||
|
|
- `CHUNK_ENTER`: repacked payload as `cx: i32, cz: i32` (8 bytes)
|
||
|
|
- Fragment assembly keyed by `(cx, cz)` instead of `id`
|
||
|
|
|
||
|
|
## Removals
|
||
|
|
|
||
|
|
- `generate_connected`, `LayoutMode::Connected` — replaced by biome system
|
||
|
|
- `remap_bsp_materials` — each biome sets its own materials
|
||
|
|
- `carve_corridor_h_offset` / `carve_corridor_v_offset` — no more combined grids
|
||
|
|
- `main.rs` single-BSP generation on spawn — replaced by streaming around player position
|
||
|
|
|
||
|
|
## What Stays
|
||
|
|
|
||
|
|
- `generate_rooms` / `generate_courtyard` — used as chunk-level biome generators
|
||
|
|
- Door system (`pxl8_sim_door`, `door_angle`, `entities.fnl`) — chunk-local feature
|
||
|
|
- `grid_to_bsp` pipeline — gains `origin_x/origin_z` parameter for world-space offset
|
||
|
|
- `grid_to_bsp` heights parameter for exterior terrain elevation
|
||
|
|
- BSP PVS, cell portals — per-chunk visibility still works
|
||
|
|
- Chunk cache (512 entries), fragment assembly, UDP transport
|