diff --git a/src/World/Section.cpp b/src/World/Section.cpp index aac2b11..23b0ebf 100644 --- a/src/World/Section.cpp +++ b/src/World/Section.cpp @@ -82,18 +82,28 @@ PaletteSection::PaletteSection( const std::shared_ptr §ion, std::shared_ptr &&blockStates0, const std::shared_ptr &paletteData, - uint32_t dataVersion -) : Section(section), blockStates(blockStates0) { - if (blockStates->getLength() % 64) + uint32_t dataVersion0 +) : Section(section), blockStates(blockStates0), dataVersion(dataVersion0) { + bits = 4; + while ((1u << bits) < paletteData->size()) { + bits++; + + if (bits > 12) + throw std::invalid_argument("unsupported block palette size"); + } + + unsigned expectedLength; + + if (dataVersion < 2529) { + expectedLength = 64 * bits; + } else { + unsigned blocksPerWord = (64 / bits); + expectedLength = (4096 + blocksPerWord - 1) / blocksPerWord; + } + + if (blockStates->getLength() != expectedLength) throw std::invalid_argument("corrupt section data"); - bits = blockStates->getLength() / 64; - if (bits > 16) - throw std::invalid_argument("unsupported block state bits"); - - mask = (1u << bits) - 1; - - for (const auto &entry : *paletteData) { const NBT::CompoundTag &paletteEntry = *assertValue(dynamic_cast(entry.get())); std::string name = assertValue(paletteEntry.get("Name"))->getValue(); @@ -107,9 +117,20 @@ PaletteSection::PaletteSection( } const Resource::BlockType * PaletteSection::getBlockStateAt(size_t x, size_t y, size_t z) const { - size_t index = bits * getIndex(x, y, z); - size_t pos = index >> 3; - size_t shift = index & 7; + size_t index = getIndex(x, y, z); + size_t bitIndex; + + if (dataVersion < 2529) { + bitIndex = bits * index; + } else { + unsigned blocksPerWord = (64 / bits); + size_t word = index / blocksPerWord; + bitIndex = 64 * word + bits * (index % blocksPerWord); + } + + size_t pos = bitIndex >> 3; + size_t shift = bitIndex & 7; + uint16_t mask = (1u << bits) - 1; uint32_t v = blockStates->getPointer()[mangleByteIndex(pos)]; diff --git a/src/World/Section.hpp b/src/World/Section.hpp index 58c3799..7e90acb 100644 --- a/src/World/Section.hpp +++ b/src/World/Section.hpp @@ -112,8 +112,8 @@ class PaletteSection : public Section { private: std::shared_ptr blockStates; std::vector palette; - size_t bits; - uint16_t mask; + uint32_t dataVersion; + unsigned bits; static const Resource::BlockType * lookup(const std::string &name, uint32_t dataVersion); @@ -127,7 +127,7 @@ public: const std::shared_ptr §ion, std::shared_ptr &&blockStates0, const std::shared_ptr &paletteData, - uint32_t dataVersion + uint32_t dataVersion0 ); virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const;