World & Terrain
The voxel chunk streaming, decoding, and meshing pipeline that builds the client’s terrain.
Terrain is streamed from zone-server as voxel chunks, decoded, meshed off the main thread, and
rendered incrementally with distance-limited collision. The whole pipeline lives in
src/Game/World/ and is entirely C#.
graph TD A[zone-server] -->|WorldInfoSMSG / ChunkManifestSMSG / ChunkDataSMSG / ChunkPatchSMSG| B[ChunkStreamManager] B -->|budgeted decode per frame| C[VoxelChunk] C --> D[ClientChunkStore] D --> E[TerrainRenderer] E -->|Task.Run, off main thread| F[SurfaceNets meshing] F -->|main thread, budgeted installs per frame| G[MeshInstance3D + StaticBody3D collider]
Streaming
ChunkStreamManager.cs is attached as a C# node listening on the same BnetSocket.MessageReceived signal used by
Networking, filtering for map-related messages
(WorldInfoSMSG/ChunkManifestSMSG/ChunkDataSMSG/ChunkPatchSMSG). Decoding is budgeted —
only DecodesPerFrame chunks are processed per frame — so a large batch of incoming chunks (e.g.
right after login) doesn’t spike a single frame. Decoded chunks are pushed into ClientChunkStore
and TerrainRenderer.Invalidate is called to schedule a re-mesh.
ChunkEngine.cs holds a single Version constant that must match the server’s world-generation
version; a mismatch is logged loudly (wrong materials/shape would otherwise render silently
wrong) rather than failing outright.
Chunk data
A decoded VoxelChunk (VoxelChunk.cs) holds parallel Blocks/Occupancy byte arrays: a material id plus a
0–255 fill amount per voxel, so a surface at a fractional height renders smoothly instead of
stair-stepping. RleCodec and ChunkPatchCodec (RleCodec.cs, ChunkPatchCodec.cs) handle the wire (de)compression and incremental
patch application (a ChunkPatchSMSG updates part of an already-streamed chunk, e.g. after
terrain is dug or built on, without re-sending the whole chunk).
Meshing
Mesh/SurfaceNets.cs, Mesh/ChunkSurface.cs and Mesh/BlockAppearance.cs implement
Surface Nets, turning the raw
voxel grid plus a material-appearance palette into vertex/normal/color/index arrays — smooth
surfaces rather than blocky Minecraft-style cubes, while still being a per-voxel grid underneath.
Rendering
TerrainRenderer.cs keeps one MeshInstance3D (plus an optional separate water mesh, and a StaticBody3D collider)
per chunk key. Meshing work runs on background Task.Run thread-pool workers, bounded by
MeshJobs; finished meshes are installed on the main thread, bounded by InstallsPerFrame — both
caps exist for the same reason ChunkStreamManager’s decode budget does: keep any single frame
from spiking. Colliders are only built within CollisionRadiusChunks of the player
(SetCollisionAnchorAt), since a StaticBody3D per distant, never-walked-on chunk would be
wasted physics-engine overhead.
Ground & pathing
Scripts under src/Game/Ground/:
walkable_floor.gdis attached to every collision body — both a placeholder flat ground used outside streamed areas and the code-built chunk colliders above — puts it in the"floor"group, and relays clicks toMouseManager(see Interaction).path_calculator.gd(PathCalculator.calculate_tile_path) generates a simple diagonal-then- straight tile path client-side from a single click, with no collision awareness — it’s a client-side approximation for immediate visual feedback, not the authoritative path (movement is still driven by the server’sPathComponentSMSG, see Entity Sync).
Last updated 19 Sep 2026, 01:24 +0200 .