1 /** 2 Copyright: Copyright (c) 2013-2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.client.chunkman; 7 8 import std.experimental.logger; 9 import std.datetime : StopWatch, Duration; 10 11 import dlib.math.vector : vec3, ivec3; 12 13 import voxelman.client.chunkmeshman; 14 import voxelman.core.block; 15 import voxelman.core.blockman; 16 import voxelman.core.config; 17 import voxelman.storage.chunk; 18 import voxelman.storage.chunkstorage; 19 import voxelman.storage.coordinates; 20 import voxelman.storage.utils; 21 import voxelman.storage.volume; 22 23 /// 24 struct ChunkMan 25 { 26 ChunkStorage chunkStorage; 27 alias chunkStorage this; 28 29 // Stats 30 size_t totalLoadedChunks; 31 32 Volume visibleVolume; 33 ChunkWorldPos observerPosition; 34 int viewRadius = DEFAULT_VIEW_RADIUS; 35 36 BlockMan blockMan; 37 ChunkMeshMan chunkMeshMan; 38 39 void init(uint numWorkers) 40 { 41 blockMan.loadBlockTypes(); 42 chunkMeshMan.init(&this, &blockMan, numWorkers); 43 chunkStorage.onChunkRemovedHandlers ~= &chunkMeshMan.onChunkRemoved; 44 } 45 46 void stop() 47 { 48 info("unloading chunks"); 49 50 foreach(chunk; chunkStorage.chunks.byValue) 51 chunkStorage.removeQueue.add(chunk); 52 53 while(chunkStorage.chunks.length > 0) 54 { 55 chunkStorage.update(); 56 } 57 58 chunkMeshMan.stop(); 59 } 60 61 void update() 62 { 63 chunkMeshMan.update(); 64 chunkStorage.update(); 65 } 66 67 void onChunkLoaded(ChunkWorldPos chunkPos, BlockData blockData) 68 { 69 Chunk* chunk = chunkStorage.getChunk(chunkPos); 70 71 // We can receive data for chunk that is already deleted. 72 if (chunk is null || chunk.isMarkedForDeletion) 73 { 74 blockData.deleteBlocks(); 75 return; 76 } 77 78 chunkMeshMan.onChunkLoaded(chunk, blockData); 79 } 80 81 void onChunkChanged(Chunk* chunk, BlockChange[] changes) 82 { 83 chunkMeshMan.onChunkChanged(chunk, changes); 84 } 85 86 Volume calcVolume(ChunkWorldPos position) 87 { 88 auto size = viewRadius*2 + 1; 89 return Volume(cast(ivec3)(position.vector - viewRadius), 90 ivec3(size, size, size)); 91 } 92 93 void updateObserverPosition(vec3 cameraPos) 94 { 95 ChunkWorldPos chunkPos = BlockWorldPos(cameraPos); 96 observerPosition = chunkPos; 97 98 Volume newVolume = calcVolume(chunkPos); 99 if (newVolume == visibleVolume) return; 100 101 updateVisibleVolume(newVolume); 102 } 103 104 void updateVisibleVolume(Volume newVolume) 105 { 106 auto oldVolume = visibleVolume; 107 visibleVolume = newVolume; 108 109 if (oldVolume.empty) 110 { 111 loadVolume(newVolume); 112 return; 113 } 114 115 auto trisectResult = trisect(oldVolume, newVolume); 116 auto chunksToRemove = trisectResult.aPositions; 117 auto chunksToLoad = trisectResult.bPositions; 118 119 // remove chunks 120 foreach(chunkPos; chunksToRemove) 121 { 122 chunkStorage 123 .removeQueue 124 .add(chunkStorage.getChunk(ChunkWorldPos(chunkPos))); 125 } 126 127 // load chunks 128 foreach(chunkPos; chunksToLoad) 129 { 130 chunkStorage.loadChunk(ChunkWorldPos(chunkPos)); 131 } 132 } 133 134 void loadVolume(Volume volume) 135 { 136 import std.algorithm : each; 137 volume.positions.each!(pos => chunkStorage.loadChunk(ChunkWorldPos(pos))); 138 } 139 }