1 /**
2 Copyright: Copyright (c) 2013-2018 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 voxelman.log;
9 
10 import voxelman.container.sharedhashset;
11 import voxelman.world.block;
12 import voxelman.core.config;
13 import voxelman.thread.worker;
14 import voxelman.world.storage.coordinates;
15 import voxelman.world.storage.chunk.layer;
16 import voxelman.world.storage.chunk.chunkprovider : TaskId, TASK_CANCELED_METADATA;
17 
18 import voxelman.world.gen.utils;
19 import voxelman.world.gen.generator;
20 
21 //version = DBG_OUT;
22 void chunkGenWorkerThread(
23 	shared(Worker)* workerInfo,
24 	shared SharedHashSet!TaskId canceledTasks,
25 	BlockInfoTable blockInfos)
26 {
27 	import std.array : uninitializedArray;
28 
29 	ubyte[] compressBuffer = uninitializedArray!(ubyte[])(CHUNK_SIZE_CUBE*BlockId.sizeof);
30 	try
31 	{
32 		while (workerInfo.needsToRun)
33 		{
34 			workerInfo.waitForNotify();
35 
36 			if (!workerInfo.taskQueue.empty)
37 			{
38 				TaskId taskId = workerInfo.taskQueue.popItem!TaskId();
39 				ulong _cwp = workerInfo.taskQueue.popItem!ulong();
40 				ChunkWorldPos cwp = ChunkWorldPos(_cwp);
41 				IGenerator generator = workerInfo.taskQueue.popItem!IGenerator();
42 
43 				if (canceledTasks[taskId])
44 				{
45 					workerInfo.resultQueue.startMessage();
46 					workerInfo.resultQueue.pushMessagePart(taskId);
47 					workerInfo.resultQueue.pushMessagePart(ChunkHeaderItem(cwp, 0, TASK_CANCELED_METADATA));
48 					workerInfo.resultQueue.endMessage();
49 
50 					continue;
51 				}
52 
53 				genChunk(taskId, cwp, &workerInfo.resultQueue,
54 					generator, blockInfos, compressBuffer);
55 			}
56 		}
57 	}
58 	catch(Throwable t)
59 	{
60 		import std.conv : to;
61 		infof("%s from gen worker", t.to!string);
62 		throw t;
63 	}
64 	version(DBG_OUT)infof("Gen worker stopped");
65 }
66 
67 //version = DBG_COMPR;
68 void genChunk(
69 	TaskId taskId,
70 	ChunkWorldPos cwp,
71 	shared(SharedQueue)* resultQueue,
72 	IGenerator generator,
73 	BlockInfoTable blockInfos,
74 	ubyte[] compressBuffer)
75 {
76 	BlockId[CHUNK_SIZE_CUBE] blocks;
77 	ChunkGeneratorResult chunk = generator.generateChunk(
78 		cwp.xyz, blocks);
79 
80 	enum layerId = BLOCK_LAYER;
81 	enum timestamp = 0;
82 	enum numLayers = 1;
83 
84 	resultQueue.startMessage();
85 	resultQueue.pushMessagePart(taskId);
86 	resultQueue.pushMessagePart(ChunkHeaderItem(cwp, numLayers));
87 
88 	if(chunk.uniform)
89 	{
90 		ushort metadata = calcChunkFullMetadata(chunk.uniformBlockId, blockInfos);
91 		auto layer = ChunkLayerItem(layerId,
92 			BLOCKID_UNIFORM_FILL_BITS, timestamp,
93 			chunk.uniformBlockId, metadata);
94 		resultQueue.pushMessagePart(layer);
95 	}
96 	else
97 	{
98 		ushort metadata = calcChunkFullMetadata(blocks, blockInfos);
99 		ubyte[] compactBlocks = compressLayerData(cast(ubyte[])blocks, compressBuffer);
100 		StorageType storageType = StorageType.compressedArray;
101 		ubyte[] data = allocLayerArray(compactBlocks);
102 
103 		auto layer = ChunkLayerItem(storageType, layerId, timestamp, data, metadata);
104 		resultQueue.pushMessagePart(layer);
105 	}
106 	resultQueue.endMessage();
107 }