diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/NBT/ByteArrayTag.hpp | 11 | ||||
-rw-r--r-- | src/World/Chunk.cpp | 64 | ||||
-rw-r--r-- | src/World/Chunk.hpp | 98 |
3 files changed, 74 insertions, 99 deletions
diff --git a/src/NBT/ByteArrayTag.hpp b/src/NBT/ByteArrayTag.hpp index 4f2d331..0e56a9a 100644 --- a/src/NBT/ByteArrayTag.hpp +++ b/src/NBT/ByteArrayTag.hpp @@ -55,15 +55,8 @@ public: return len; } - const uint8_t & get(size_t i) const { - return value[i]; - } - - uint8_t getHalf(size_t i) const { - if (i % 2) - return (value[i/2] >> 4); - else - return (value[i/2] & 0xf); + const uint8_t * getValue() const { + return value; } }; diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp index c3c15f8..5a6f95b 100644 --- a/src/World/Chunk.cpp +++ b/src/World/Chunk.cpp @@ -30,6 +30,7 @@ #include <iostream> #include <stdexcept> #include <cstdlib> +#include <cstring> #include <zlib.h> @@ -101,27 +102,32 @@ void Chunk::analyzeChunk() { if (!lightPopulatedTag && lightPopulatedTag->getValue()) throw std::invalid_argument("light data missing"); - for (auto §ion : *assertValue(level->get<NBT::ListTag<NBT::CompoundTag>>("Sections"))) - sections.emplace_back(*section); + sections = assertValue(level->get<NBT::ListTag<NBT::CompoundTag>>("Sections")); + maxY = (assertValue(sections->back()->get<NBT::ByteTag>("Y"))->getValue() + 1) * SIZE; - maxY = sections.back().getY() + SIZE; - blocks.reset(new Block[maxY * SIZE * SIZE]); + blockIDs.reset(new uint8_t[maxY * SIZE * SIZE]); + blockData.reset(new uint8_t[maxY * SIZE * SIZE / 2]); + blockSkyLight.reset(new uint8_t[maxY * SIZE * SIZE / 2]); + blockBlockLight.reset(new uint8_t[maxY * SIZE * SIZE / 2]); - for (auto §ion : sections) { - unsigned Y = section.getY(); + std::memset(blockSkyLight.get(), 0xff, maxY * SIZE * SIZE / 2); - for (size_t y = 0; y < SIZE; y++) { - for (size_t z = 0; z < SIZE; z++) { - for (size_t x = 0; x < SIZE; x++) { - Block &block = getBlock(x, Y+y, z); - block.id = section.getBlockAt(x, y, z); - block.data = section.getDataAt(x, y, z); - block.blockLight = section.getBlockLightAt(x, y, z); - block.skyLight = section.getSkyLightAt(x, y, z); - } - } - } + for (auto §ion : *sections) { + std::shared_ptr<const NBT::ByteArrayTag> blocks = assertValue(section->get<NBT::ByteArrayTag>("Blocks")); + std::shared_ptr<const NBT::ByteArrayTag> data = assertValue(section->get<NBT::ByteArrayTag>("Data")); + std::shared_ptr<const NBT::ByteArrayTag> blockLight = assertValue(section->get<NBT::ByteArrayTag>("BlockLight")); + std::shared_ptr<const NBT::ByteArrayTag> skyLight = assertValue(section->get<NBT::ByteArrayTag>("SkyLight")); + size_t Y = assertValue(section->get<NBT::ByteTag>("Y"))->getValue(); + + if (blocks->getLength() != SIZE*SIZE*SIZE || data->getLength() != SIZE*SIZE*SIZE/2 + || blockLight->getLength() != SIZE*SIZE*SIZE/2 || skyLight->getLength() != SIZE*SIZE*SIZE/2) + throw std::invalid_argument("corrupt chunk data"); + + std::memcpy(blockIDs.get() + Y*SIZE*SIZE*SIZE, blocks->getValue(), SIZE*SIZE*SIZE); + std::memcpy(blockData.get() + Y*SIZE*SIZE*SIZE/2, data->getValue(), SIZE*SIZE*SIZE/2); + std::memcpy(blockBlockLight.get() + Y*SIZE*SIZE*SIZE/2, blockLight->getValue(), SIZE*SIZE*SIZE/2); + std::memcpy(blockSkyLight.get() + Y*SIZE*SIZE*SIZE/2, skyLight->getValue(), SIZE*SIZE*SIZE/2); } } @@ -138,29 +144,27 @@ Chunk::Blocks Chunk::getTopLayer() const { if (ret.blocks[x][z].id) continue; - const Block &block = getBlock(x, y, z); - if (!BLOCK_TYPES[block.id].opaque) + uint8_t id = getBlockAt(x, y, z); + if (!BLOCK_TYPES[id].opaque) continue; Block &b = ret.blocks[x][z]; - b.id = block.id; - b.data = block.data; + b.id = id; + b.data = getDataAt(x, y, z); - const Block *lightBlock; - if (y < maxY-1) - lightBlock = &getBlock(x, y+1, z); - else - lightBlock = █ + size_t y2 = y; + if (y2 < maxY-1) + y2++; - b.blockLight = lightBlock->blockLight; - b.skyLight = lightBlock->skyLight; + b.blockLight = getBlockLightAt(x, y2, z); + b.skyLight = getSkyLightAt(x, y2, z); unsigned h; for (h = y; h > 0; h--) { - const Block &block2 = getBlock(x, h, z); - if (block2.id != 8 && block2.id != 9) + uint8_t id2 = getBlockAt(x, h, z); + if (id2 != 8 && id2 != 9) break; } diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp index 333d5e5..a4948b7 100644 --- a/src/World/Chunk.hpp +++ b/src/World/Chunk.hpp @@ -47,83 +47,61 @@ class Chunk { public: static const size_t SIZE = 16; - class Section { - private: - static size_t getIndex(size_t x, size_t y, size_t z) { - if (x >= SIZE || y >= SIZE || z >= SIZE) - throw std::range_error("Chunk::getIndex(): bad coordinates"); - - return SIZE*SIZE*y + SIZE*z + x; - } - - std::shared_ptr<const NBT::ByteArrayTag> blocks; - std::shared_ptr<const NBT::ByteArrayTag> data; - - std::shared_ptr<const NBT::ByteArrayTag> blockLight; - std::shared_ptr<const NBT::ByteArrayTag> skyLight; - - unsigned Y; - - public: - Section(const NBT::CompoundTag &s) { - blocks = assertValue(s.get<NBT::ByteArrayTag>("Blocks")); - data = assertValue(s.get<NBT::ByteArrayTag>("Data")); - blockLight = assertValue(s.get<NBT::ByteArrayTag>("BlockLight")); - skyLight = assertValue(s.get<NBT::ByteArrayTag>("SkyLight")); - - if (blocks->getLength() != SIZE*SIZE*SIZE || data->getLength() != SIZE*SIZE*SIZE/2 - || blockLight->getLength() != SIZE*SIZE*SIZE/2 || skyLight->getLength() != SIZE*SIZE*SIZE/2) - throw std::invalid_argument("corrupt chunk data"); - - Y = assertValue(s.get<NBT::ByteTag>("Y"))->getValue() * SIZE; - } - - uint8_t getBlockAt(size_t x, size_t y, size_t z) const { - return blocks->get(getIndex(x, y, z)); - } - - uint8_t getDataAt(size_t x, size_t y, size_t z) const { - return data->getHalf(getIndex(x, y, z)); - } - - uint8_t getBlockLightAt(size_t x, size_t y, size_t z) const { - return blockLight->getHalf(getIndex(x, y, z)); - } - - uint8_t getSkyLightAt(size_t x, size_t y, size_t z) const { - return skyLight->getHalf(getIndex(x, y, z)); - } - - unsigned getY() const { - return Y; - } - }; - struct Blocks { Block blocks[SIZE][SIZE]; }; + private: size_t len; UniqueCPtr<uint8_t[]> data; std::shared_ptr<const NBT::CompoundTag> root; std::shared_ptr<const NBT::CompoundTag> level; + std::shared_ptr<const NBT::ListTag<NBT::CompoundTag>> sections; - std::vector<Section> sections; unsigned maxY; - std::unique_ptr<Block[]> blocks; + std::unique_ptr<uint8_t[]> blockIDs; + std::unique_ptr<uint8_t[]> blockData; + std::unique_ptr<uint8_t[]> blockSkyLight; + std::unique_ptr<uint8_t[]> blockBlockLight; + - Block & getBlock(size_t x, size_t y, size_t z) { - return blocks[SIZE*SIZE*y + SIZE*z + x]; + size_t getIndex(size_t x, size_t y, size_t z) const { + if (x >= SIZE || y >= maxY || z >= SIZE) + throw std::range_error("Chunk::getIndex(): bad coordinates"); + + return SIZE*SIZE*y + SIZE*z + x; } - const Block & getBlock(size_t x, size_t y, size_t z) const { - return blocks[SIZE*SIZE*y + SIZE*z + x]; + uint8_t getHalf(const uint8_t *v, size_t x, size_t y, size_t z) const { + size_t i = getIndex(x, y, z); + + if (i % 2) + return (v[i/2] >> 4); + else + return (v[i/2] & 0xf); } + uint8_t getBlockAt(size_t x, size_t y, size_t z) const { + return blockIDs[getIndex(x, y, z)]; + } + + uint8_t getDataAt(size_t x, size_t y, size_t z) const { + return getHalf(blockData.get(), x, y, z); + } + + uint8_t getBlockLightAt(size_t x, size_t y, size_t z) const { + return getHalf(blockBlockLight.get(), x, y, z); + } + + uint8_t getSkyLightAt(size_t x, size_t y, size_t z) const { + return getHalf(blockSkyLight.get(), x, y, z); + } + + void inflateChunk(Buffer buffer); void parseChunk(); void analyzeChunk(); @@ -135,8 +113,8 @@ public: return *level; } - const std::vector<Section> & getSections() const { - return sections; + const NBT::ListTag<NBT::CompoundTag> & getSections() const { + return *sections; } Blocks getTopLayer() const; |