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.world.gen.worker;
7
8 import std.experimental.logger;
9
10 import voxelman.block.utils;
11 import voxelman.core.config;
12 import voxelman.utils.worker;
13 import voxelman.world.storage.coordinates;
14 import voxelman.world.storage.chunk;
15
16 import voxelman.world.gen.utils;
17 import voxelman.world.gen.generator;
18
19 //version = DBG_OUT;
20 void chunkGenWorkerThread(shared(Worker)* workerInfo, BlockInfoTable blockInfos)
21 {
22 import std.array : uninitializedArray;
23
24 ubyte[] compressBuffer = uninitializedArray!(ubyte[])(CHUNK_SIZE_CUBE*BlockId.sizeof);
25 try
26 {
27 while (workerInfo.needsToRun)
28 {
29 workerInfo.waitForNotify();
30
31 if (!workerInfo.taskQueue.empty)
32 {
33 ulong _cwp = workerInfo.taskQueue.popItem!ulong();
34 ChunkWorldPos cwp = ChunkWorldPos(_cwp);
35 IGenerator generator = workerInfo.taskQueue.popItem!IGenerator();
36 genChunk(cwp, &workerInfo.resultQueue,
37 generator, blockInfos, compressBuffer);
38 }
39 }
40 }
41 catch(Throwable t)
42 {
43 import std.conv : to;
44 infof("%s from gen worker", t.to!string);
45 throw t;
46 }
47 version(DBG_OUT)infof("Gen worker stopped");
48 }
49
50 //version = DBG_COMPR;
51 void genChunk(
52 ChunkWorldPos cwp,
53 shared(SharedQueue)* resultQueue,
54 IGenerator generator,
55 BlockInfoTable blockInfos,
56 ubyte[] compressBuffer)
57 {
58 BlockId[CHUNK_SIZE_CUBE] blocks;
59 ChunkGeneratorResult chunk = generator.generateChunk(
60 cwp.xyz, blocks);
61
62 enum layerId = FIRST_LAYER;
63 enum timestamp = 0;
64 enum numLayers = 1;
65
66 resultQueue.startMessage();
67 auto header = ChunkHeaderItem(cwp, numLayers);
68 resultQueue.pushMessagePart(header);
69
70 if(chunk.uniform)
71 {
72 ushort metadata = calcChunkFullMetadata(chunk.uniformBlockId, blockInfos);
73 auto layer = ChunkLayerItem(StorageType.uniform, layerId,
74 BLOCKID_UNIFORM_FILL_BITS, timestamp,
75 chunk.uniformBlockId, metadata);
76 resultQueue.pushMessagePart(layer);
77 }
78 else
79 {
80 ushort metadata = calcChunkFullMetadata(blocks, blockInfos);
81
82 ubyte[] compactBlocks = compressLayerData(cast(ubyte[])blocks, compressBuffer);
83
84 StorageType storageType;
85 LayerDataLenType dataLength;
86 ubyte* data;
87
88 if (compactBlocks.length <= LayerDataLenType.max)
89 {
90 version(DBG_COMPR)infof("Gen1 %s %s %s\n(%(%02x%))", cwp, compactBlocks.ptr, compactBlocks.length, cast(ubyte[])compactBlocks);
91 compactBlocks = compactBlocks.dup;
92 version(DBG_COMPR)infof("Gen2 %s %s %s\n(%(%02x%))", cwp, compactBlocks.ptr, compactBlocks.length, cast(ubyte[])compactBlocks);
93 dataLength = cast(LayerDataLenType)compactBlocks.length;
94 data = cast(ubyte*)compactBlocks.ptr;
95 storageType = StorageType.compressedArray;
96 }
97 else
98 {
99 infof("Gen non-compressed %s", cwp);
100 dataLength = cast(LayerDataLenType)blocks.length;
101 assert(dataLength == CHUNK_SIZE_CUBE);
102 data = cast(ubyte*)blocks.dup.ptr;
103 storageType = StorageType.fullArray;
104 }
105
106 // Add root to data.
107 // Data can be collected by GC if no-one is referencing it.
108 // It is needed to pass array trough shared queue.
109 // Root is removed inside ChunkProvider
110 import core.memory : GC;
111 GC.addRoot(data); // TODO remove when moved to non-GC allocator
112 auto layer = ChunkLayerItem(storageType, layerId, dataLength, timestamp, data, metadata);
113 resultQueue.pushMessagePart(layer);
114 }
115 resultQueue.endMessage();
116 }