The world coordinates follow a convention where +X is east, +Y is north, and +Z is skyward. The world is divided into vertical chunks, each with 16x16x128 blocks in size, extending from the world's z = 0 to z = 128. Chunks are positioned on a 2D grid using chunk coordinates, with adjacent chunks having consecutive coordinate values. Each chunk is responsible for managing its own set of blocks, stored in a 1D array instead of a vector, for optimal memory usage and access speed. The chunk system employs a flyweight pattern for blocks, with each block occupying only 3 bytes of memory.
The chunk architecture also supports efficient rendering through the use of a vertex buffer. Each chunk maintains its own vertex buffer, avoiding rendering blocks separately and optimizing the communication between CPU and GPU. Hidden surface removal is implemented at the chunk level, further improving rendering performance by culling unnecessary faces and reducing 95% of triangles.
Bit-Chunk Data - Using Bits to store block's coordinates
Player interaction with the world centers around two primary mechanics: digging and block placement. Using a 3D raycast system that extends from the camera position forward, players can target blocks up to a certain distance. This raycast employs a 3D version of the Fast Voxel Raycast algorithm, optimized for the chunked world architecture using BlockIterators to traverse between blocks, even across chunk boundaries, efficiently.
When a player targets a block, its surface is visually highlighted. Left-clicking converts the targeted block to air (digging), while right-clicking places a block of the currently selected type adjacent to the targeted surface. These simple interactions have complex implications for the world:
Digging through a ceiling can create a shaft of sunlight that streams down to the floor below as the lighting system propagates skylighting through the newly created opening
Placing an opaque block can seal off light sources, plunging areas into darkness
Placing light-emitting blocks like glowstone creates new light sources that illuminate surrounding areas
Each block modification marks the affected chunk as "dirty," requiring its mesh to be rebuilt and flagged for saving to disk.
The chunk generation system is built on the JobSystem that manages worker threads for asynchronous operations:
Multiple worker threads are created during initialization (typically one fewer than the number of CPU cores)
A dedicated ChunkGenerateJob class handles the actual block generation process
The system maintains separate queues for pending, executing, and completed jobs
The main thread handles final chunk activation and integration after generation is complete
Each chunk maintains an atomic state enum to track its status through the generation pipeline, allowing the system to coordinate work across threads safely.
When activated, a chunk is terrain is generated using a world seed that ensures consistent generation across play sessions. The generation process begins with determining the terrain height for each column using 2D Perlin noise with multiple octaves, creating natural-looking hills and valleys. This base height map is then modified by several biome factors, each controlled by Perlin noise functions.
Humidity, temperature, hilliness, and oceanness are calculated for each column using separate Perlin noise functions with different seeds (derived from the world seed). These factors create distinct biomes - dry areas become deserts with sand replacing grass and dirt, cold regions feature ice instead of water, hillier areas have more dramatic elevation changes, and oceanic regions create large bodies of water.
Rivers are cleverly implemented using the absolute value of terrain height Perlin noise, which creates natural-looking waterways that follow the zero-crossing lines of the noise function—beaches form where grass blocks meet the ocean at low humidity levels, creating shorelines.
I also generate trees using a local maxima approach in the noise field. A tree is placed at a location only if its noise value is the highest among its surrounding columns, ensuring natural-looking tree distribution. Different biomes produce different types of trees—deserts have cacti, cold regions have spruce trees, and temperate areas have standard trees.
Additionally, my approach to cave generation combines Perlin noise and controlled randomness to create organic-looking tunnel systems. Each cave starts from randomly selected points within the chunk and then "worms" its way through the terrain following noise-guided directional changes. This approach ensures that caves turn gradually and naturally rather than making sharp, unrealistic angles. Using different seed offsets for yaw and pitch (+11 and +12) creates independent noise patterns for horizontal and vertical movement, with the pitch changes intentionally dampened (50° vs 100° for yaw) to favor more horizontal exploration.
The cave generation process works in sections, each with a randomly determined length. This creates varied tunnel segments that combine as "worms." It also includes a maximum cave length parameter to prevent caves from becoming too extensive and potentially destabilizing the world generation. The function below creates cylindrical or capsule-shaped tunnels along the cave path, removing blocks to form the actual cave space. The variable cave radius parameter allows for tunnels that can narrow and widen.