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 }