diff --git a/examples/dminer/src/dminer/core/chunk.d b/examples/dminer/src/dminer/core/chunk.d new file mode 100644 index 00000000..33332bcb --- /dev/null +++ b/examples/dminer/src/dminer/core/chunk.d @@ -0,0 +1,451 @@ +module dminer.core.chunk; + +import dminer.core.minetypes; +import dminer.core.blocks; + +enum USE_NEW_WORLD_IMPL = true; + + +// Y range: 0..CHUNK_DY-1 +immutable int CHUNK_DY_SHIFT = 7; +immutable int CHUNK_DY = (1<= _chunkCount) + return null; + return _chunks[idx]; + } + @property int topNonEmptyY() { + return ((_minChunkY + _chunkCount) << 3) - 1; + } + void set(int chunkY, SmallChunk * item) { + int idx = chunkY - _minChunkY; + if (idx >= 0 && idx < _chunkCount) { + if (_chunks[idx]) { + if (_chunks[idx] is item) + return; + SmallChunk.free(_chunks[idx]); + } + _chunks[idx] = item; + return; + } else if (!_chunkCount) { + // need to reallocate + // initial allocation + _minChunkY = chunkY; + _chunkCount = 1; + _chunks = allocChunks(1); + _chunks[0] = item; + } else { + // need to reallocate + // realloc + int newMinY; + int newChunkCount; + if (chunkY < _minChunkY) { + newMinY = chunkY; + newChunkCount = _minChunkY + _chunkCount - newMinY; + } else { + newMinY = _minChunkY; + newChunkCount = chunkY - _minChunkY + 1; + } + SmallChunk ** newChunks = allocChunks(newChunkCount); + // copy old data + for(int i = 0; i < _chunkCount; i++) + newChunks[i + _minChunkY - newMinY] = _chunks[i]; + newChunks[chunkY - newMinY] = item; + freeChunks(_chunks); + _chunkCount = newChunkCount; + _minChunkY = newMinY; + _chunks = newChunks; + } + } + private SmallChunk ** allocChunks(int len) { + if (len <= 0) + return null; + import core.stdc.stdlib : malloc; + SmallChunk ** res = cast(SmallChunk **) malloc(len * (SmallChunk *).sizeof); + for(int i = 0; i < len; i++) + res[i] = null; + return res; + } + private void freeChunks(ref SmallChunk ** chunks) { + if (chunks) { + import core.stdc.stdlib : free; + free(chunks); + chunks = null; + } + } + void clear() { + if (_chunkCount) { + for(int i = 0; i < _chunkCount; i++) { + SmallChunk.free(_chunks[i]); + } + freeChunks(_chunks); + } + _chunks = null; + _chunkCount = 0; + _minChunkY = -1; + } + ~this() { + clear(); + } +} + +/// 8x8x8 chunk +struct SmallChunk { + cell_t[8*8*8] cells; // 512 bytes + ubyte[8*8*8] sunlight; // 512 bytes + ulong[8] opaquePlanesX; // 64 bytes + ulong[8] opaquePlanesY; // 64 bytes + ulong[8] opaquePlanesZ; // 64 bytes + ulong[8] canPassPlanesX; // 64 bytes + ulong[8] canPassPlanesY; // 64 bytes + ulong[8] canPassPlanesZ; // 64 bytes + ulong[6][6] canPassFromTo; // 288 bytes + SmallChunk * [6] nearChunks; + bool dirty; + + static SmallChunk * alloc() nothrow @nogc { + import core.stdc.stdlib : malloc; + SmallChunk * res = cast(SmallChunk *)malloc(SmallChunk.sizeof); + *res = SmallChunk.init; + return res; + } + + static void free(SmallChunk * obj) { + if (!obj) + return; + import core.stdc.stdlib : free; + free(obj); + } + + cell_t getCell(int x, int y, int z) const { + return cells[((((y&7) << 3) | (z&7)) << 3) | (x&7)]; + } + void setCell(int x, int y, int z, cell_t value) { + dirty = true; + cells[((((y&7) << 3) | (z&7)) << 3) | (x&7)] = value; + } + cell_t getCellNoCheck(int x, int y, int z) const { + return cells[(((y << 3) | z) << 3) | x]; + } + void generateMasks() { + // x planes: z,y + for(int x = 0; x < 8; x++) { + ulong opaqueFlags = 0; + ulong canPassFlags = 0; + ulong mask = 1; + for (int y = 0; y < 8; y++) { + for (int z = 0; z < 8; z++) { + cell_t cell = cells[(((y << 3) | z) << 3) | x]; + if (BLOCK_TYPE_OPAQUE.ptr[cell]) + opaqueFlags |= mask; + if (BLOCK_TYPE_CAN_PASS.ptr[cell]) + canPassFlags |= mask; + mask = mask << 1; + } + } + opaquePlanesX[x] = opaqueFlags; + canPassPlanesX[x] = canPassFlags; + } + // y planes : x,z + for(int y = 0; y < 8; y++) { + ulong opaqueFlags = 0; + ulong canPassFlags = 0; + ulong mask = 1; + for (int z = 0; z < 8; z++) { + for (int x = 0; x < 8; x++) { + cell_t cell = cells[(((y << 3) | z) << 3) | x]; + if (BLOCK_TYPE_OPAQUE.ptr[cell]) + opaqueFlags |= mask; + if (BLOCK_TYPE_CAN_PASS.ptr[cell]) + canPassFlags |= mask; + mask = mask << 1; + } + } + opaquePlanesY[y] = opaqueFlags; + canPassPlanesY[y] = canPassFlags; + } + // z planes: x,y + for(int z = 0; z < 8; z++) { + ulong opaqueFlags = 0; + ulong canPassFlags = 0; + ulong mask = 1; + for (int y = 0; y < 8; y++) { + for (int x = 0; x < 8; x++) { + cell_t cell = cells[(((y << 3) | z) << 3) | x]; + if (BLOCK_TYPE_OPAQUE.ptr[cell]) + opaqueFlags |= mask; + if (BLOCK_TYPE_CAN_PASS.ptr[cell]) + canPassFlags |= mask; + mask = mask << 1; + } + } + opaquePlanesZ[z] = opaqueFlags; + canPassPlanesZ[z] = canPassFlags; + } + // can pass from to + for (Dir from = Dir.min; from <= Dir.max; ++from) { + for (Dir to = Dir.min; to <= Dir.max; ++to) { + } + } + dirty = false; + } + static void spreadFlags(ulong src, ref ulong[8] planes, ref ulong[8] dst, int start, int end, ubyte spreadMask) { + if (start < end) { + for (int i = start; i <= end; ++i) { + ulong mask = src; + if (spreadMask & SpreadMask.SpreadLeft) + mask |= ((src << 1) & 0xFEFEFEFEFEFEFEFE); + if (spreadMask & SpreadMask.SpreadRight) + mask |= ((src >> 1) & 0x7F7F7F7F7F7F7F7F); + if (spreadMask & SpreadMask.SpreadUp) + mask |= ((src << 8) & 0xFFFFFFFFFFFFFF00); + if (spreadMask & SpreadMask.SpreadDown) + mask |= ((src >> 8) & 0x00FFFFFFFFFFFFFF); + src = planes[i] & mask; + dst[i] = src; + } + } else { + for (int i = end; i >= start; --i) { + ulong mask = src; + if (spreadMask & SpreadMask.SpreadLeft) + mask |= ((src << 1) & 0xFEFEFEFEFEFEFEFE); + if (spreadMask & SpreadMask.SpreadRight) + mask |= ((src >> 1) & 0x7F7F7F7F7F7F7F7F); + if (spreadMask & SpreadMask.SpreadUp) + mask |= ((src << 8) & 0xFFFFFFFFFFFFFF00); + if (spreadMask & SpreadMask.SpreadDown) + mask |= ((src >> 8) & 0x00FFFFFFFFFFFFFF); + src = planes[i] & mask; + dst[i] = src; + } + } + } + + ulong canPass(ulong mask, Dir dir, Dir to, ubyte dirMask = DirMask.MASK_ALL) { + ulong[8] planes; + ubyte spreadMask = DIR_AND_MASK_TO_SPREAD_FLAGS[dirMask][dir]; + final switch(dir) with (Dir) { + case NORTH: + spreadFlags(mask, canPassPlanesZ, planes, 0, 7, spreadMask); + final switch (to) { + case NORTH: + return planes[7]; + case SOUTH: + return planes[0]; + case EAST: + return slicePlane7(planes); + case WEST: + return slicePlane0(planes); + case UP: + return slicePlane7(planes); + case DOWN: + return slicePlane0(planes); + } + case SOUTH: + spreadFlags(mask, canPassPlanesZ, planes, 7, 0, spreadMask); + final switch (to) { + case NORTH: + return planes[7]; + case SOUTH: + return planes[0]; + case EAST: + return slicePlane7(planes); + case WEST: + return slicePlane0(planes); + case UP: + return slicePlane7(planes); + case DOWN: + return slicePlane0(planes); + } + case WEST: + spreadFlags(mask, canPassPlanesX, planes, 7, 0, spreadMask); + final switch (to) { + case NORTH: + return slicePlane7(planes); + case SOUTH: + return slicePlane0(planes); + case EAST: + return planes[7]; + case WEST: + return planes[0]; + case UP: + return slicePlane7(planes); + case DOWN: + return slicePlane0(planes); + } + case EAST: + spreadFlags(mask, canPassPlanesX, planes, 0, 7, spreadMask); + final switch (to) { + case NORTH: + return slicePlane7(planes); + case SOUTH: + return slicePlane0(planes); + case EAST: + return planes[7]; + case WEST: + return planes[0]; + case UP: + return slicePlane7(planes); + case DOWN: + return slicePlane0(planes); + } + case UP: + spreadFlags(mask, canPassPlanesY, planes, 0, 7, spreadMask); + final switch (to) { + case NORTH: + return slicePlane7(planes); + case SOUTH: + return slicePlane0(planes); + case EAST: + return slicePlane7(planes); + case WEST: + return slicePlane0(planes); + case UP: + return planes[7]; + case DOWN: + return planes[0]; + } + case DOWN: + spreadFlags(mask, canPassPlanesY, planes, 7, 0, spreadMask); + final switch (to) { + case NORTH: + return slicePlane7(planes); + case SOUTH: + return slicePlane0(planes); + case EAST: + return slicePlane7(planes); + case WEST: + return slicePlane0(planes); + case UP: + return planes[7]; + case DOWN: + return planes[0]; + } + } + } + + static ulong slicePlane0(ref ulong[8] planes) { + ulong res = 0; + for (int i = 0; i < 8; i++) { + res |= (planes[i] & 0x0101010101010101) << i; + } + return res; + } + + static ulong slicePlane7(ref ulong[8] planes) { + ulong res = 0; + for (int i = 0; i < 8; i++) { + res |= (planes[i] & 0x8080808080808080) >> (7 - i); + } + return res; + } +} + +enum SpreadMask : ubyte { + SpreadLeft = 1, + SpreadRight = 2, + SpreadUp = 4, + SpreadDown = 8, +} + +ubyte dirMaskToSpreadMask(Dir dir, ubyte dirMask) { + ubyte res = 0; + final switch (dir) with (Dir) { + case NORTH: // from north + case SOUTH: + res |= (dirMask & DirMask.MASK_UP) ? SpreadMask.SpreadUp : 0; + res |= (dirMask & DirMask.MASK_DOWN) ? SpreadMask.SpreadDown : 0; + res |= (dirMask & DirMask.MASK_EAST) ? SpreadMask.SpreadLeft : 0; + res |= (dirMask & DirMask.MASK_WEST) ? SpreadMask.SpreadRight : 0; + break; + case WEST: + case EAST: + res |= (dirMask & DirMask.MASK_UP) ? SpreadMask.SpreadUp : 0; + res |= (dirMask & DirMask.MASK_DOWN) ? SpreadMask.SpreadDown : 0; + res |= (dirMask & DirMask.MASK_NORTH) ? SpreadMask.SpreadLeft : 0; + res |= (dirMask & DirMask.MASK_SOUTH) ? SpreadMask.SpreadRight : 0; + break; + case UP: + case DOWN: + res |= (dirMask & DirMask.MASK_EAST) ? SpreadMask.SpreadLeft : 0; + res |= (dirMask & DirMask.MASK_WEST) ? SpreadMask.SpreadRight : 0; + res |= (dirMask & DirMask.MASK_NORTH) ? SpreadMask.SpreadUp : 0; + res |= (dirMask & DirMask.MASK_SOUTH) ? SpreadMask.SpreadDown : 0; + break; + } + return res; +} + +// immutable SpreadMask[DirMask][Dir] DIR_AND_MASK_TO_SPREAD_FLAGS +mixin(generateDirMaskSource()); + +string generateDirMaskSource() { + import std.conv : to; + char[] src; + src ~= "immutable ubyte[64][6] DIR_AND_MASK_TO_SPREAD_FLAGS = [\n"; + for (Dir from = Dir.min; from <= Dir.max; from++) { + if (from) + src ~= ",\n"; + src ~= " // "; + src ~= to!string(from); + src ~= "\n ["; + for (ubyte mask = 0; mask < 64; mask++) { + ubyte res = dirMaskToSpreadMask(from, mask); + if (mask) + src ~= ", "; + if (mask == 32) + src ~= "\n "; + src ~= to!string(res); + } + src ~= "]"; + } + src ~= "\n];\n"; + return src.dup; +} + +void testDirMaskToSpreadMask() { + import dlangui.core.logger; + for (Dir from = Dir.min; from <= Dir.max; from++) { + for (ubyte mask = 0; mask < 64; mask++) { + ubyte res = dirMaskToSpreadMask(from, mask); + char[]buf; + buf ~= "["; + if (mask & DirMask.MASK_NORTH) buf ~= " NORTH"; + if (mask & DirMask.MASK_SOUTH) buf ~= " SOUTH"; + if (mask & DirMask.MASK_WEST) buf ~= " WEST"; + if (mask & DirMask.MASK_EAST) buf ~= " EAST"; + if (mask & DirMask.MASK_UP) buf ~= " UP"; + if (mask & DirMask.MASK_DOWN) buf ~= " DOWN"; + buf ~= " ] => ("; + if (res & SpreadMask.SpreadLeft) buf ~= " SpreadLeft"; + if (res & SpreadMask.SpreadRight) buf ~= " SpreadRight"; + if (res & SpreadMask.SpreadUp) buf ~= " SpreadUp"; + if (res & SpreadMask.SpreadDown) buf ~= " SpreadDown"; + buf ~= " )"; + Log.d("dirMaskToSpreadMask ", from, " ", buf); + } + } + Log.d("Source: \n", generateDirMaskSource()); +}