World Streaming
@esengine/world-streaming provides chunk-based world streaming and management for open world games. It handles dynamic loading/unloading of world chunks based on player position.
Installation
Section titled “Installation”npm install @esengine/world-streamingQuick Start
Section titled “Quick Start”Basic Setup
Section titled “Basic Setup”import { ChunkManager, ChunkStreamingSystem, StreamingAnchorComponent, ChunkLoaderComponent} from '@esengine/world-streaming';
// Create chunk manager (512 unit chunks)const chunkManager = new ChunkManager(512);chunkManager.setScene(scene);
// Add streaming systemconst streamingSystem = new ChunkStreamingSystem();streamingSystem.setChunkManager(chunkManager);scene.addSystem(streamingSystem);
// Create loader entity with configconst loaderEntity = scene.createEntity('ChunkLoader');const loader = loaderEntity.addComponent(new ChunkLoaderComponent());loader.chunkSize = 512;loader.loadRadius = 2;loader.unloadRadius = 4;
// Create player as streaming anchorconst playerEntity = scene.createEntity('Player');const anchor = playerEntity.addComponent(new StreamingAnchorComponent());
// Update anchor position each framefunction update() { anchor.x = player.position.x; anchor.y = player.position.y;}Procedural Generation
Section titled “Procedural Generation”import type { IChunkDataProvider, IChunkCoord, IChunkData } from '@esengine/world-streaming';
class ProceduralChunkProvider implements IChunkDataProvider { private seed: number;
constructor(seed: number) { this.seed = seed; }
async loadChunkData(coord: IChunkCoord): Promise<IChunkData | null> { // Use deterministic random based on seed + coord const chunkSeed = this.hashCoord(coord); const rng = this.createRNG(chunkSeed);
// Generate chunk content const entities = this.generateEntities(coord, rng);
return { coord, entities, version: 1 }; }
async saveChunkData(data: IChunkData): Promise<void> { // Optional: persist modified chunks }
private hashCoord(coord: IChunkCoord): number { return this.seed ^ (coord.x * 73856093) ^ (coord.y * 19349663); }
private createRNG(seed: number) { // Simple seeded random return () => { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; }; }
private generateEntities(coord: IChunkCoord, rng: () => number) { // Generate resources, trees, etc. return []; }}
// Use providerchunkManager.setDataProvider(new ProceduralChunkProvider(12345));Core Concepts
Section titled “Core Concepts”Chunk Lifecycle
Section titled “Chunk Lifecycle”Unloaded → Loading → Loaded → Unloading → Unloaded ↓ ↓ Failed (on error)Streaming Anchor
Section titled “Streaming Anchor”StreamingAnchorComponent marks entities as chunk loading anchors. The system loads chunks around all anchors and unloads chunks outside the combined range.
// StreamingAnchorComponent implements IPositionableinterface IPositionable { readonly position: { x: number; y: number };}Configuration
Section titled “Configuration”| Property | Default | Description |
|---|---|---|
chunkSize | 512 | Chunk size in world units |
loadRadius | 2 | Chunks to load around anchor |
unloadRadius | 4 | Chunks to unload beyond this |
maxLoadsPerFrame | 2 | Max async loads per frame |
unloadDelay | 3000 | MS before unloading |
bEnablePrefetch | true | Prefetch in movement direction |
Module Setup (Optional)
Section titled “Module Setup (Optional)”For quick setup, use the module helper:
import { worldStreamingModule } from '@esengine/world-streaming';
const chunkManager = worldStreamingModule.setup( scene, services, componentRegistry, { chunkSize: 256, bEnableCulling: true });Documentation
Section titled “Documentation”- Chunk Manager API - Loading queue, chunk lifecycle
- Streaming System - Anchor-based loading
- Serialization - Custom chunk serialization
- Examples - Procedural worlds, MMO chunks