summaryrefslogtreecommitdiffstats
path: root/src/World/Chunk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/World/Chunk.cpp')
-rw-r--r--src/World/Chunk.cpp130
1 files changed, 52 insertions, 78 deletions
diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp
index d4c6029..50ac81e 100644
--- a/src/World/Chunk.cpp
+++ b/src/World/Chunk.cpp
@@ -25,14 +25,11 @@
#include "Chunk.hpp"
-#include "../Resource/BlockType.hpp"
+#include "../NBT/ListTag.hpp"
+#include "../NBT/StringTag.hpp"
-#include <iostream>
-#include <stdexcept>
-#include <cstdlib>
#include <cstring>
-
-#include <zlib.h>
+#include <stdexcept>
namespace MinedMap {
@@ -41,100 +38,77 @@ namespace World {
Chunk::Chunk(const ChunkData *data) {
level = assertValue(data->getRoot().get<NBT::CompoundTag>("Level"));
- std::shared_ptr<const NBT::ByteTag> lightPopulatedTag = level->get<NBT::ByteTag>("LightPopulated");
- bool lightPopulated = lightPopulatedTag && lightPopulatedTag->getValue();
+ std::shared_ptr<const NBT::ListTag> sectionsTag = level->get<NBT::ListTag>("Sections");
+ if (!sectionsTag)
+ return;
- sections = assertValue(level->get<NBT::ListTag>("Sections"));
- const NBT::CompoundTag *lastSection = assertValue(dynamic_cast<const NBT::CompoundTag *>(sections->back().get()));
- maxY = (assertValue(lastSection->get<NBT::ByteTag>("Y"))->getValue() + 1) * SIZE;
+ biomeBytes = level->get<NBT::ByteArrayTag>("Biomes");
+ biomeInts = level->get<NBT::IntArrayTag>("Biomes");
+ assertValue(biomeBytes || biomeInts);
-
- std::shared_ptr<const NBT::ByteArrayTag> biomeTag = assertValue(level->get<NBT::ByteArrayTag>("Biomes"));
- if (biomeTag->getLength() != SIZE*SIZE)
+ if (biomeBytes && biomeBytes->getLength() != SIZE*SIZE)
+ throw std::invalid_argument("corrupt biome data");
+ else if (biomeInts && biomeInts->getLength() != SIZE*SIZE)
throw std::invalid_argument("corrupt biome data");
- biomes = biomeTag->getValue();
-
- 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]);
-
- std::memset(blockIDs.get(), 0, maxY * SIZE * SIZE);
- std::memset(blockData.get(), 0, maxY * SIZE * SIZE / 2);
- std::memset(blockSkyLight.get(), 0xff, maxY * SIZE * SIZE / 2);
- std::memset(blockBlockLight.get(), 0, maxY * SIZE * SIZE / 2);
-
-
- for (auto &sectionTag : *sections) {
- const NBT::CompoundTag *section = assertValue(dynamic_cast<const NBT::CompoundTag *>(sectionTag.get()));
- 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"));
- size_t Y = assertValue(section->get<NBT::ByteTag>("Y"))->getValue();
-
- if (blocks->getLength() != SIZE*SIZE*SIZE || data->getLength() != SIZE*SIZE*SIZE/2)
- throw std::invalid_argument("corrupt chunk data");
-
- if (lightPopulated) {
- 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"));
+ for (auto &sTag : *sectionsTag) {
+ auto s = std::dynamic_pointer_cast<const NBT::CompoundTag>(sTag);
+ std::unique_ptr<Section> section = Section::makeSection(s);
+ size_t Y = section->getY();
+ sections.resize(Y);
+ sections.push_back(std::move(section));
+ }
+}
- if (blockLight->getLength() != SIZE*SIZE*SIZE/2 || skyLight->getLength() != SIZE*SIZE*SIZE/2)
- throw std::invalid_argument("corrupt chunk data");
+bool Chunk::getBlock(Block *block, const Section *section, size_t x, size_t y, size_t z, uint8_t prev_light) const {
+ if (block->height > 0)
+ return false;
- 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);
- }
+ const Resource::BlockType *type = section->getBlockStateAt(x, y, z);
+ if (!type || !type->opaque)
+ return false;
- 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);
+ if (!block->type) {
+ block->type = type;
+ block->blockLight = prev_light;
+ block->biome = getBiomeAt(x, z);
}
-}
-Block Chunk::getBlock(size_t x, size_t y, size_t z) const {
- size_t y2 = y;
- if (y2 < maxY-1)
- y2++;
+ if (type->blue)
+ return false;
- unsigned h;
- for (h = y; h > 0; h--) {
- uint8_t id2 = getBlockAt(x, h, z);
- if (id2 != 8 && id2 != 9)
- break;
- }
+ block->height = SIZE*section->getY() + y;
- return Block(
- getBlockAt(x, y, z),
- getDataAt(x, y, z),
- h,
- getBlockLightAt(x, y2, z),
- getSkyLightAt(x, y2, z),
- getBiomeAt(x, z)
- );
+ return true;
}
Chunk::Blocks Chunk::getTopLayer() const {
size_t done = 0;
- Blocks ret;
+ Blocks ret = {};
+ uint8_t prev_light[SIZE][SIZE] = {};
- for (ssize_t y = maxY-1; y >= 0; y--) {
+ for (ssize_t Y = sections.size() - 1; Y >= 0; Y--) {
if (done == SIZE*SIZE)
break;
- for (size_t z = 0; z < SIZE; z++) {
- for (size_t x = 0; x < SIZE; x++) {
- if (ret.blocks[x][z].id)
- continue;
+ if (!sections[Y]) {
+ std::memset(prev_light, 0, sizeof(prev_light));
+ continue;
+ }
+
+ const Section *section = sections[Y].get();
- uint8_t id = getBlockAt(x, y, z);
- uint8_t data = getDataAt(x, y, z);
+ for (ssize_t y = SIZE-1; y >= 0; y--) {
+ if (done == SIZE*SIZE)
+ break;
- const Resource::BlockType *type = Resource::LEGACY_BLOCK_TYPES.types[id][data];
- if (!type || !type->opaque)
- continue;
+ for (size_t z = 0; z < SIZE; z++) {
+ for (size_t x = 0; x < SIZE; x++) {
+ if (getBlock(&ret.blocks[x][z], section, x, y, z, prev_light[x][z]))
+ done++;
- ret.blocks[x][z] = getBlock(x, y, z);
- done++;
+ prev_light[x][z] = section->getBlockLightAt(x, y, z);
+ }
}
}
}