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 }