Overview
TheSave class handles world persistence (loading/saving chunks to disk) and manages chunk streaming during gameplay.
src/save.h, src/save.cpp
Constructor
Save(World* w)
Creates a save system for a world. Parameters:w- World instance to manage
- Sets
pathto"save/"directory - Creates save directory if it doesn’t exist
- Associates with the given world
Methods
save()
- Iterates through all chunks in
world->chunks - Calls
save_chunk()for each chunk - Writes NBT-compressed chunk data to
save/<rx>/<rz>/c.<x>.<z>.dat
load()
initial_radius- Number of chunks to load immediately (default: 2)
- Eager phase: Loads chunks within
initial_radiuswitheager_build=true- Performs full lighting propagation immediately
- Generates all meshes synchronously
- Ensures starting area is fully lit and rendered
- Streaming phase: Queues remaining chunks (up to render distance) with
eager_build=false- Defers lighting and meshing to future frames
- Prevents FPS drops during initial spawn
The
eager_build flag is critical for FPS stability. See Performance Optimization for details on the chunk loading improvements.update_streaming()
player_pos- Current player world position
- Converts player position to chunk coordinates
- If player moved to a new chunk:
- Queues new chunks within render distance
- Unloads chunks beyond render distance + 2
- Saves unloaded chunks to disk
main.cpp
stream_next()
max_chunks- Maximum chunks to load this frame (default: 1)
- Pops up to
max_chunksfrom the pending queue - Calls
load_chunk(pos, false)for each - Defers lighting/meshing to
World::tick()
main.cpp if has_pending_chunks()
has_pending_chunks()
true if pending_chunks queue is not empty
Usage:
Private Methods
load_chunk()
pos- Chunk positioneager_build- Iftrue, perform full lighting/meshing immediately; iffalse, defer toWorld::tick()
- Check if chunk already exists
- Create new chunk
- Attempt to read from disk via NBT
- If file not found, generate flat terrain
- If
eager_build=true:- Run full lighting propagation (no step limit)
- Build all subchunk meshes immediately
- If
eager_build=false:- Queue lighting propagation (processed via
LIGHT_STEPS_PER_TICK) - Queue mesh updates (processed via
CHUNK_UPDATES)
- Queue lighting propagation (processed via
true if chunk was loaded/generated successfully
save_chunk()
chunk- Chunk to save
save/<rx>/<rz>/c.<x>.<z>.dat
- Uses base36 encoding for region directories
true if save succeeded
See: NBT Format for file structure details
Data Members
path
"save/")
pending_chunks
- Populated by
update_streaming() - Consumed by
stream_next()
last_center_chunk
Integration Example
Typical usage inmain.cpp:
Performance Considerations
- Synchronous I/O: Chunk loading/saving blocks the main thread
- eager_build flag: Critical for FPS stability
true: Use only for initial spawn area (small radius)false: Use for streaming during gameplay
- Unload distance: Chunks beyond
render_distance + 2are unloaded and saved
See Also
- Save System - Detailed persistence architecture
- NBT Format - File format documentation
- Performance Optimization - Chunk loading improvements