1 /** 2 Copyright: Copyright (c) 2015-2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.storage.chunkprovider; 7 8 import core.thread : thread_joinAll; 9 import std.concurrency : Tid, thisTid, send, receiveTimeout; 10 import std.datetime : msecs; 11 import std.experimental.logger; 12 13 import dlib.math.vector; 14 15 import voxelman.core.chunkgen; 16 import voxelman.core.config; 17 import voxelman.storage.chunk; 18 import voxelman.storage.chunkstorage; 19 import voxelman.storage.coordinates; 20 import voxelman.storage.storageworker; 21 import voxelman.storage.world; 22 import voxelman.utils.workergroup; 23 24 25 struct SnapshotLoadedMessage 26 { 27 ChunkWorldPos cwp; 28 BlockDataSnapshot snapshot; 29 } 30 31 struct SnapshotSavedMessage 32 { 33 ChunkWorldPos cwp; 34 BlockDataSnapshot snapshot; 35 } 36 37 struct LoadSnapshotMessage 38 { 39 ChunkWorldPos cwp; 40 BlockType[] blockBuffer; 41 Tid genWorker; 42 } 43 44 struct SaveSnapshotMessage 45 { 46 ChunkWorldPos cwp; 47 BlockDataSnapshot snapshot; 48 } 49 50 struct ChunkProvider 51 { 52 private: 53 WorkerGroup!(chunkGenWorkerThread) genWorkers; 54 WorkerGroup!(storageWorkerThread) storeWorker; 55 56 public: 57 void delegate(ChunkWorldPos, BlockDataSnapshot)[] onChunkLoadedHandlers; 58 void delegate(ChunkWorldPos, TimestampType)[] onChunkSavedHandlers; 59 size_t loadQueueLength; 60 61 size_t loadQueueSpaceAvaliable() @property const 62 { 63 return MAX_LOAD_QUEUE_LENGTH - loadQueueLength; 64 } 65 66 void init(string worldDir, uint numWorkers) 67 { 68 genWorkers.startWorkers(numWorkers, thisTid); 69 storeWorker.startWorkers(1, thisTid, worldDir~"/regions"); 70 } 71 72 void stop() 73 { 74 genWorkers.stopWorkers(); 75 storeWorker.stopWorkersWhenDone(); 76 } 77 78 void update() 79 { 80 bool message = true; 81 while (message) 82 { 83 message = receiveTimeout(0.msecs, 84 (immutable(SnapshotLoadedMessage)* message) { 85 auto m = cast(SnapshotLoadedMessage*)message; 86 --loadQueueLength; 87 foreach(handler; onChunkLoadedHandlers) 88 handler(m.cwp, m.snapshot); 89 }, 90 (immutable(SnapshotSavedMessage)* message) { 91 auto m = cast(SnapshotSavedMessage*)message; 92 foreach(handler; onChunkSavedHandlers) 93 handler(m.cwp, m.snapshot.timestamp); 94 } 95 ); 96 } 97 } 98 99 void loadChunk(ChunkWorldPos cwp, BlockType[] blockBuffer) { 100 auto m = new LoadSnapshotMessage(cwp, blockBuffer, genWorkers.nextWorker); 101 storeWorker.nextWorker.send(cast(immutable(LoadSnapshotMessage)*)m); 102 ++loadQueueLength; 103 } 104 105 void saveChunk(ChunkWorldPos cwp, BlockDataSnapshot snapshot) { 106 auto m = new SaveSnapshotMessage(cwp, snapshot); 107 storeWorker.nextWorker.send(cast(immutable(SaveSnapshotMessage)*)m); 108 } 109 }