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 }