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.storage.chunk;
7 
8 import std.experimental.logger;
9 import std.array : uninitializedArray;
10 import std.string : format;
11 import std.typecons : Nullable;
12 
13 import cbor;
14 import voxelman.math;
15 import voxelman.geometry.box;
16 
17 import voxelman.core.config;
18 import voxelman.block.utils;
19 import voxelman.core.chunkmesh;
20 import voxelman.world.storage.coordinates;
21 import voxelman.world.storage.utils;
22 import voxelman.utils.compression;
23 
24 enum FIRST_LAYER = 0;
25 enum ENTITY_LAYER = 1;
26 enum BLOCKS_DATA_LENGTH = CHUNK_SIZE_CUBE * BlockId.sizeof;
27 enum BLOCKID_UNIFORM_FILL_BITS = bitsToUniformLength(BlockId.sizeof * 8);
28 
29 
30 ubyte bitsToUniformLength(ubyte bits) {
31 	if (bits == 1)
32 		return 1;
33 	else if (bits == 2)
34 		return 2;
35 	else if (bits == 4)
36 		return 3;
37 	else if (bits == 8)
38 		return 4;
39 	else if (bits == 16)
40 		return 5;
41 	else if (bits == 32)
42 		return 6;
43 	else if (bits == 64)
44 		return 7;
45 	else
46 		assert(false);
47 }
48 
49 /// is used as array size when non-uniform.
50 /// Used to allocate full array when uniform.
51 /// Assumes array length as CHUNK_SIZE_CUBE, but element size is dataLength/CHUNK_SIZE_CUBE if CHUNK_SIZE_CUBE > dataLength
52 /// Or CHUNK_SIZE_CUBE/dataLength otherwise. Element size is used to fill created array.
53 /// If dataLength < CHUNK_SIZE_CUBE then element size is less than byte.
54 /// Element size must be power of two, either of bytes or of bits.
55 alias LayerDataLenType = uint;
56 
57 enum StorageType : ubyte
58 {
59 	uniform,
60 	//linearMap,
61 	//hashMap,
62 	compressedArray,
63 	fullArray,
64 }
65 
66 ubyte[] allocLayerArray(size_t length) {
67 	return uninitializedArray!(ubyte[])(length);
68 }
69 
70 void freeLayerArray(Layer)(ref Layer layer) {
71 	import core.memory : GC;
72 	assert(layer.type != StorageType.uniform);
73 	GC.free(layer.dataPtr);
74 	layer.dataPtr = null;
75 	layer.dataLength = 0;
76 }
77 
78 struct ChunkHeaderItem {
79 	ChunkWorldPos cwp;
80 	uint numLayers;
81 	uint metadata; // for task purposes
82 }
83 static assert(ChunkHeaderItem.sizeof == 16);
84 
85 struct ChunkLayerTimestampItem {
86 	uint timestamp;
87 	ubyte layerId;
88 }
89 static assert(ChunkLayerTimestampItem.sizeof == 8);
90 
91 /// Stores layer of chunk data. Used for transferring and saving chunk layers.
92 /// Stores layerId. Stores no user count.
93 align(1)
94 struct ChunkLayerItem
95 {
96 	StorageType type;
97 	ubyte layerId;
98 	ushort metadata;
99 	uint timestamp;
100 	union {
101 		ulong uniformData;
102 		void* dataPtr; /// Stores ptr to the first byte of data. The length of data is in dataLength.
103 	}
104 
105 	LayerDataLenType dataLength;
106 	this(StorageType _type, ubyte _layerId, LayerDataLenType _dataLength, uint _timestamp, ulong _uniformData, ushort _metadata = 0) {
107 		type = _type; layerId = _layerId; dataLength = _dataLength; timestamp = _timestamp; uniformData = _uniformData; metadata = _metadata;
108 	}
109 	this(StorageType _type, ubyte _layerId, LayerDataLenType _dataLength, uint _timestamp, ubyte* _dataPtr, ushort _metadata = 0) {
110 		type = _type; layerId = _layerId; dataLength = _dataLength; timestamp = _timestamp; dataPtr = _dataPtr; metadata = _metadata;
111 	}
112 	this(T)(StorageType _type, ubyte _layerId, uint _timestamp, T[] _array, ushort _metadata = 0) {
113 		ubyte[] data = cast(ubyte[])_array;
114 		type = _type; layerId = _layerId; dataLength = cast(LayerDataLenType)data.length; timestamp = _timestamp; dataPtr = cast(void*)data.ptr; metadata = _metadata;
115 	}
116 	this(ChunkLayerSnap l, ubyte _layerId) {
117 		type = l.type;
118 		layerId = _layerId;
119 		dataLength = l.dataLength;
120 		timestamp = l.timestamp;
121 		uniformData = l.uniformData;
122 		metadata = l.metadata;
123 	}
124 
125 	void toString()(scope void delegate(const(char)[]) sink) const
126 	{
127 		import std.format : formattedWrite;
128 		sink.formattedWrite("ChunkLayerItem(%s, %s, %s, %s, {%s, %s}, %s)",
129 			type, layerId, dataLength, timestamp, uniformData, dataPtr, metadata);
130 	}
131 }
132 static assert(ChunkLayerItem.sizeof == 20);
133 
134 struct WriteBuffer
135 {
136 	ChunkLayerItem layer;
137 	bool isModified = true;
138 
139 	this(Layer)(Layer _layer) if (isSomeLayer!Layer) {
140 		if (_layer.type == StorageType.uniform) {
141 			makeUniform(_layer.uniformData, _layer.dataLength, _layer.metadata);
142 		} else {
143 			applyLayer(_layer, layer);
144 		}
145 	}
146 
147 	void makeUniform(ulong uniformData, LayerDataLenType dataLength, ushort metadata = 0) {
148 		if (!isUniform) {
149 			freeLayerArray(layer);
150 		}
151 		layer.uniformData = uniformData;
152 		layer.dataLength = dataLength;
153 		layer.metadata = metadata;
154 	}
155 
156 	void makeUniform(T)(ulong uniformData, ushort metadata = 0) {
157 		if (!isUniform) {
158 			freeLayerArray(layer);
159 		}
160 		layer.uniformData = uniformData;
161 		layer.dataLength = bitsToUniformLength(T.sizeof * 8);
162 		layer.metadata = metadata;
163 	}
164 
165 	bool isUniform() {
166 		return layer.type == StorageType.uniform;
167 	}
168 
169 	T getUniform(T)() {
170 		return layer.getUniform!T;
171 	}
172 
173 	T[] getArray(T)() {
174 		return layer.getArray!T;
175 	}
176 }
177 
178 void applyLayer(Layer1, Layer2)(const Layer1 layer, ref Layer2 writeBuffer)
179 	if (isSomeLayer!Layer1 && isSomeLayer!Layer2)
180 {
181 	ubyte[] buffer;
182 	if (layer.type == StorageType.uniform)
183 	{
184 		// zero is used to denote that uniform cannot be expanded and should produce empty array.
185 		assert(layer.dataLength >= 0 && layer.dataLength <= 7,
186 			format("dataLength == %s", layer.dataLength));
187 		if (layer.dataLength > 0)
188 		{
189 			size_t itemBitsPowerOfTwo = layer.dataLength - 1; // [1; 7] => [0; 6]
190 			size_t itemBits = 1 << itemBitsPowerOfTwo; // [1..64]
191 			size_t arraySize = (CHUNK_SIZE_CUBE * itemBits) / 8;
192 
193 			buffer = ensureLayerArrayLength(writeBuffer, arraySize);
194 			expandUniform(buffer, cast(ubyte)itemBits, layer.uniformData);
195 		}
196 		else
197 		{
198 			// empty array
199 		}
200 	}
201 	else if (layer.type == StorageType.fullArray)
202 	{
203 		buffer = ensureLayerArrayLength(writeBuffer, layer.dataLength);
204 		buffer[] = layer.getArray!ubyte;
205 	}
206 	else if (layer.type == StorageType.compressedArray)
207 	{
208 		ubyte[] compressedData = layer.getArray!ubyte;
209 		size_t uncompressedLength = uncompressedDataLength(compressedData);
210 		buffer = ensureLayerArrayLength(writeBuffer, uncompressedLength);
211 		ubyte[] decompressedData = decompress(compressedData, buffer);
212 		assert(decompressedData.length == buffer.length);
213 	}
214 	writeBuffer.type = StorageType.fullArray;
215 	writeBuffer.metadata = layer.metadata;
216 	writeBuffer.dataPtr = buffer.ptr;
217 	writeBuffer.dataLength = cast(LayerDataLenType)buffer.length;
218 }
219 
220 ubyte[] ensureLayerArrayLength(Layer)(ref Layer layer, size_t length)
221 	if (isSomeLayer!Layer)
222 {
223 	ubyte[] buffer;
224 	if (layer.isUniform)
225 	{
226 		buffer = allocLayerArray(length);
227 	}
228 	else
229 	{
230 		if (layer.dataLength == length)
231 		{
232 			buffer = layer.getArray!ubyte;
233 		}
234 		else
235 		{
236 			freeLayerArray(layer); // TODO realloc
237 			buffer = allocLayerArray(length);
238 		}
239 	}
240 	return buffer;
241 }
242 
243 // tables of repeated bit patterns for 1, 2 and 4 bit items.
244 private static immutable ubyte[2] bitsTable1 = [0b0000_0000, 0b1111_1111];
245 private static immutable ubyte[4] bitsTable2 = [0b00_00_00_00, 0b01_01_01_01, 0b10_10_10_10, 0b11_11_11_11];
246 private static immutable ubyte[16] bitsTable4 = [
247 0b0000_0000, 0b0001_0001, 0b0010_0010, 0b0011_0011, 0b0100_0100, 0b0101_0101, 0b0110_0110, 0b0111_0111,
248 0b1000_1000, 0b1001_1001, 0b1010_1010, 0b1011_1011, 0b1100_1100, 0b1101_1101, 0b1110_1110, 0b1111_1111];
249 
250 void expandUniform(ubyte[] buffer, ubyte itemBits, ulong uniformData)
251 {
252 	switch(itemBits) {
253 		case 1:
254 			ubyte byteFiller = bitsTable1[uniformData & 0b0001];
255 			buffer[] = byteFiller;
256 			break;
257 		case 2:
258 			ubyte byteFiller = bitsTable2[uniformData & 0b0011];
259 			buffer[] = byteFiller;
260 			break;
261 		case 4:
262 			ubyte byteFiller = bitsTable4[uniformData & 0b1111];
263 			buffer[] = byteFiller;
264 			break;
265 		case 8:
266 			ubyte byteFiller = uniformData & ubyte.max;
267 			buffer[] = byteFiller;
268 			break;
269 		case 16:
270 			ushort ushortFiller = uniformData & ushort.max;
271 			(cast(ushort[])buffer)[] = ushortFiller;
272 			break;
273 		case 32:
274 			uint uintFiller = uniformData & uint.max;
275 			(cast(uint[])buffer)[] = uintFiller;
276 			break;
277 		case 64:
278 			ulong ulongFiller = uniformData & ulong.max;
279 			(cast(ulong[])buffer)[] = ulongFiller;
280 			break;
281 		default:
282 			assert(false, "Invalid itemBits");
283 	}
284 }
285 
286 /// Container for chunk updates
287 /// If blockChanges is null uses newBlockData
288 struct ChunkChange
289 {
290 	uvec3 a, b; // box
291 	BlockId blockId;
292 }
293 
294 // container of single block change.
295 // position is chunk local [0; CHUNK_SIZE-1];
296 struct BlockChange
297 {
298 	ushort index;
299 	BlockId blockId;
300 }
301 
302 ushort[2] areaOfImpact(BlockChange[] changes)
303 {
304 	ushort start;
305 	ushort end;
306 
307 	foreach(change; changes)
308 	{
309 		if (change.index < start)
310 			start = change.index;
311 		if (change.index > end)
312 			end = change.index;
313 	}
314 
315 	return cast(ushort[2])[start, end+1];
316 }
317 
318 // stores all used snapshots of the chunk.
319 struct BlockDataSnapshot
320 {
321 	BlockData blockData;
322 	TimestampType timestamp;
323 	uint numUsers;
324 }
325 
326 /// Stores layer of chunk data. Blocks are stored as array of blocks or uniform.
327 struct ChunkLayerSnap
328 {
329 	union {
330 		ulong uniformData;
331 		void* dataPtr; /// Stores ptr to the first byte of data. The length of data is in dataLength.
332 	}
333 	LayerDataLenType dataLength; // unused when uniform
334 	uint timestamp;
335 	ushort numUsers;
336 	ushort metadata;
337 	StorageType type;
338 	this(StorageType _type, LayerDataLenType _dataLength, uint _timestamp, ulong _uniformData, ushort _metadata = 0) {
339 		type = _type; dataLength = _dataLength; timestamp = _timestamp; uniformData = _uniformData; metadata = _metadata;
340 	}
341 	this(StorageType _type, LayerDataLenType _dataLength, uint _timestamp, void* _dataPtr, ushort _metadata = 0) {
342 		type = _type; dataLength = _dataLength; timestamp = _timestamp; dataPtr = _dataPtr; metadata = _metadata;
343 	}
344 	this(T)(StorageType _type, uint _timestamp, T[] _array, ushort _metadata = 0) {
345 		ubyte[] data = cast(ubyte[])_array;
346 		type = _type; dataLength = cast(LayerDataLenType)data.length; timestamp = _timestamp; dataPtr = data.ptr; metadata = _metadata;
347 	}
348 	this(ChunkLayerItem l) {
349 		numUsers = 0;
350 		timestamp = l.timestamp;
351 		type = l.type;
352 		dataLength = l.dataLength;
353 		uniformData = l.uniformData;
354 		metadata = l.metadata;
355 	}
356 }
357 
358 enum isSomeLayer(Layer) = is(Layer == ChunkLayerSnap) || is(Layer == ChunkLayerItem) || is(Layer == Nullable!ChunkLayerSnap);
359 
360 T[] getArray(T, Layer)(const ref Layer layer)
361 	if (isSomeLayer!Layer)
362 {
363 	assert(layer.type != StorageType.uniform);
364 	return cast(T[])(layer.dataPtr[0..layer.dataLength]);
365 }
366 T getUniform(T, Layer)(const ref Layer layer)
367 	if (isSomeLayer!Layer)
368 {
369 	assert(layer.type == StorageType.uniform);
370 	return cast(T)layer.uniformData;
371 }
372 
373 BlockId getBlockId(Layer)(const ref Layer layer, BlockChunkIndex index)
374 	if (isSomeLayer!Layer)
375 {
376 	if (layer.type == StorageType.uniform) return layer.getUniform!BlockId;
377 	if (layer.type == StorageType.compressedArray) {
378 		BlockId[CHUNK_SIZE_CUBE] buffer;
379 		decompressLayerData(layer, cast(ubyte[])buffer[]);
380 		return buffer[index];
381 	}
382 	return getArray!BlockId(layer)[index];
383 }
384 
385 BlockId getBlockId(Layer)(const ref Layer layer, int x, int y, int z)
386 	if (isSomeLayer!Layer)
387 {
388 	return getBlockId(layer, BlockChunkIndex(x, y, z));
389 }
390 
391 bool isUniform(Layer)(const ref Layer layer) @property
392 	if (isSomeLayer!Layer)
393 {
394 	return layer.type == StorageType.uniform;
395 }
396 
397 BlockData toBlockData(Layer)(const ref Layer layer, ubyte layerId)
398 	if (isSomeLayer!Layer)
399 {
400 	BlockData res;
401 	res.uniform = layer.type == StorageType.uniform;
402 	res.metadata = layer.metadata;
403 	res.layerId = layerId;
404 	if (!res.uniform) {
405 		res.blocks = layer.getArray!ubyte();
406 	} else {
407 		res.uniformType = layer.uniformData;
408 		res.dataLength = layer.dataLength;
409 	}
410 	return res;
411 }
412 
413 ChunkLayerItem fromBlockData(const ref BlockData bd)
414 {
415 	if (bd.uniform)
416 		return ChunkLayerItem(StorageType.uniform, bd.layerId, bd.dataLength, 0, bd.uniformType, bd.metadata);
417 	else
418 		return ChunkLayerItem(StorageType.fullArray, bd.layerId, 0, bd.blocks, bd.metadata);
419 }
420 
421 void copyToBuffer(Layer)(Layer layer, BlockId[] outBuffer)
422 	if (isSomeLayer!Layer)
423 {
424 	assert(outBuffer.length == CHUNK_SIZE_CUBE);
425 	if (layer.type == StorageType.uniform)
426 		outBuffer[] = cast(BlockId)layer.uniformData;
427 	else if (layer.type == StorageType.fullArray)
428 		outBuffer[] = layer.getArray!BlockId;
429 	else if (layer.type == StorageType.compressedArray)
430 		decompressLayerData(layer, outBuffer);
431 }
432 
433 size_t getLayerDataBytes(Layer)(const ref Layer layer)
434 	if (isSomeLayer!Layer)
435 {
436 	if (layer.type == StorageType.uniform)
437 		return 0;
438 	else
439 		return layer.dataLength;
440 }
441 
442 void applyChanges(WriteBuffer* writeBuffer, BlockChange[] changes)
443 {
444 	assert(!writeBuffer.isUniform);
445 	assert(writeBuffer.layer.dataLength == BLOCKS_DATA_LENGTH);
446 	BlockId[] blocks = writeBuffer.layer.getArray!BlockId;
447 	foreach(change; changes)
448 	{
449 		blocks[change.index] = change.blockId;
450 	}
451 }
452 
453 void applyChanges(WriteBuffer* writeBuffer, ChunkChange[] changes)
454 {
455 	assert(!writeBuffer.isUniform);
456 	assert(writeBuffer.layer.dataLength == BLOCKS_DATA_LENGTH);
457 	BlockId[] blocks = writeBuffer.layer.getArray!BlockId;
458 	foreach(change; changes)
459 	{
460 		setSubArray(blocks, Box(ivec3(change.a), ivec3(change.b)), change.blockId);
461 	}
462 }
463 
464 void setSubArray(BlockId[] buffer, Box box, BlockId blockId)
465 {
466 	assert(buffer.length == CHUNK_SIZE_CUBE);
467 
468 	if (box.position.x == 0 && box.size.x == CHUNK_SIZE)
469 	{
470 		if (box.position.z == 0 && box.size.z == CHUNK_SIZE)
471 		{
472 			if (box.position.y == 0 && box.size.y == CHUNK_SIZE)
473 			{
474 				buffer[] = blockId;
475 			}
476 			else
477 			{
478 				auto from = box.position.y * CHUNK_SIZE_SQR;
479 				auto to = (box.position.y + box.size.y) * CHUNK_SIZE_SQR;
480 				buffer[from..to] = blockId;
481 			}
482 		}
483 		else
484 		{
485 			foreach(y; box.position.y..(box.position.y + box.size.y))
486 			{
487 				auto from = y * CHUNK_SIZE_SQR + box.position.z * CHUNK_SIZE;
488 				auto to = y * CHUNK_SIZE_SQR + (box.position.z + box.size.z) * CHUNK_SIZE;
489 				buffer[from..to] = blockId;
490 			}
491 		}
492 	}
493 	else
494 	{
495 		int posx = box.position.x;
496 		int endx = box.position.x + box.size.x;
497 		int endy = box.position.y + box.size.y;
498 		int endz = box.position.z + box.size.z;
499 		foreach(y; box.position.y..endy)
500 		foreach(z; box.position.z..endz)
501 		{
502 			auto offset = y * CHUNK_SIZE_SQR + z * CHUNK_SIZE;
503 			auto from = posx + offset;
504 			auto to = endx + offset;
505 			buffer[from..to] = blockId;
506 		}
507 	}
508 }
509 
510 ubyte[] compressLayerData(ubyte[] data, ubyte[] buffer)
511 {
512 	size_t size = encodeCbor(buffer[], data.length);
513 	size += compress(data, buffer[size..$]).length;
514 	return buffer[0..size];
515 }
516 
517 ubyte[] decompressLayerData(Layer)(const Layer layer, ubyte[] outBuffer) if (isSomeLayer!Layer)
518 {
519 	assert(layer.type == StorageType.compressedArray);
520 	return decompressLayerData(layer.getArray!ubyte, outBuffer);
521 }
522 
523 ubyte[] decompressLayerData(const ubyte[] _compressedData)
524 {
525 	ubyte[] compressedData = cast(ubyte[])_compressedData;
526 	auto dataSize = decodeCborSingle!size_t(compressedData);
527 	ubyte[] buffer = uninitializedArray!(ubyte[])(dataSize);
528 	ubyte[] decompressedData = decompress(compressedData, buffer);
529 	return decompressedData;
530 }
531 
532 // pops and returns size of uncompressed data. Modifies provided array.
533 size_t uncompressedDataLength()(auto ref ubyte[] compressedData)
534 {
535 	return decodeCborSingle!size_t(compressedData);
536 }
537 
538 ubyte[] decompressLayerData(const ubyte[] _compressedData, ubyte[] outBuffer)
539 {
540 	ubyte[] compressedData = cast(ubyte[])_compressedData;
541 	auto dataSize = decodeCborSingle!size_t(compressedData);
542 	//assert(outBuffer.length == dataSize, format("%s != %s", outBuffer.length, dataSize));
543 	ubyte[] decompressedData = decompress(compressedData, outBuffer);
544 	return decompressedData;
545 }
546 
547 // Stores blocks of the chunk.
548 struct BlockData
549 {
550 	void validate()
551 	{
552 		if (layerId == 0 && !uniform && blocks.length != BLOCKS_DATA_LENGTH) {
553 			fatalf("Size of uniform chunk != CHUNK_SIZE_CUBE, == %s", blocks.length);
554 		}
555 	}
556 
557 	/// null if uniform is true, or contains chunk data otherwise
558 	ubyte[] blocks;
559 
560 	/// type of common block
561 	ulong uniformType = 0; // Unknown block
562 
563 	/// is chunk filled with block of the same type
564 	bool uniform = true;
565 	uint dataLength;
566 
567 	ushort metadata;
568 	ubyte layerId;
569 }