summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2018-07-24 20:00:16 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2018-07-24 20:06:54 +0200
commit210f651807847c290ab7ba14c64f9eff1c47284e (patch)
tree0266a2f10a0227a02fb1473b6cd77c74824de16f
parentdd432af298e0bcaf165ac826613723f1dce4b10d (diff)
downloadMinedMap-210f651807847c290ab7ba14c64f9eff1c47284e.tar
MinedMap-210f651807847c290ab7ba14c64f9eff1c47284e.zip
World: factor out Section handling to a generic interface
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/World/Block.cpp2
-rw-r--r--src/World/Block.hpp17
-rw-r--r--src/World/Chunk.cpp130
-rw-r--r--src/World/Chunk.hpp71
-rw-r--r--src/World/Section.cpp56
-rw-r--r--src/World/Section.hpp110
7 files changed, 246 insertions, 141 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4e4d23f..2b57fa9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,6 +15,7 @@ add_executable(MinedMap
World/ChunkData.cpp
World/Level.cpp
World/Region.cpp
+ World/Section.cpp
)
set_target_properties(MinedMap PROPERTIES COMPILE_FLAGS "-std=c++11 -Wall")
target_link_libraries(MinedMap ${ZLIB_LIBRARIES} ${PNG_LIBRARIES})
diff --git a/src/World/Block.cpp b/src/World/Block.cpp
index 06017fd..b4a464b 100644
--- a/src/World/Block.cpp
+++ b/src/World/Block.cpp
@@ -26,14 +26,12 @@
#include "Block.hpp"
#include "../Resource/Biome.hpp"
-#include "../Resource/BlockType.hpp"
namespace MinedMap {
namespace World {
uint32_t Block::getColor() const {
- const Resource::BlockType *type = Resource::LEGACY_BLOCK_TYPES.types[id][data];
if (!type || !type->opaque)
return 0;
diff --git a/src/World/Block.hpp b/src/World/Block.hpp
index 4975faa..e2dcfde 100644
--- a/src/World/Block.hpp
+++ b/src/World/Block.hpp
@@ -26,28 +26,25 @@
#pragma once
-#include <cstdint>
+#include "../NBT/CompoundTag.hpp"
+#include "../Resource/BlockType.hpp"
namespace MinedMap {
namespace World {
struct Block {
- uint8_t id;
- uint8_t data;
-
+ const Resource::BlockType *type;
unsigned height;
-
uint8_t blockLight;
- uint8_t skyLight;
-
uint8_t biome;
- Block() : id(0), data(0), height(0), blockLight(0), skyLight(0), biome(0) {}
- Block(uint8_t id0, uint8_t data0, unsigned height0, uint8_t blockLight0, uint8_t skyLight0, uint8_t biome0)
- : id(id0), data(data0), height(height0), blockLight(blockLight0), skyLight(skyLight0), biome(biome0) {}
uint32_t getColor() const;
+
+ operator bool() const {
+ return type;
+ }
};
}
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);
+ }
}
}
}
diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp
index 4bd301d..8451cbe 100644
--- a/src/World/Chunk.hpp
+++ b/src/World/Chunk.hpp
@@ -29,13 +29,13 @@
#include "Block.hpp"
#include "ChunkData.hpp"
-#include "../Util.hpp"
-#include "../NBT/ListTag.hpp"
-#include "../NBT/ByteTag.hpp"
+#include "Section.hpp"
#include "../NBT/ByteArrayTag.hpp"
+#include "../NBT/IntArrayTag.hpp"
+#include "../Resource/BlockType.hpp"
+#include "../Util.hpp"
#include <cstdint>
-#include <tuple>
namespace MinedMap {
@@ -43,62 +43,27 @@ namespace World {
class Chunk {
public:
- static const size_t SIZE = 16;
+ static const size_t SIZE = Section::SIZE;
struct Blocks {
Block blocks[SIZE][SIZE];
};
-
private:
std::shared_ptr<const NBT::CompoundTag> level;
- std::shared_ptr<const NBT::ListTag> sections;
-
-
- unsigned maxY;
-
- std::unique_ptr<uint8_t[]> blockIDs;
- std::unique_ptr<uint8_t[]> blockData;
- std::unique_ptr<uint8_t[]> blockSkyLight;
- std::unique_ptr<uint8_t[]> blockBlockLight;
- const uint8_t *biomes;
+ std::vector<std::unique_ptr<Section>> sections;
+ std::shared_ptr<const NBT::ByteArrayTag> biomeBytes;
+ std::shared_ptr<const NBT::IntArrayTag> biomeInts;
- 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;
- }
-
- 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);
+ uint8_t getBiomeAt(size_t x, size_t z) const {
+ if (biomeBytes)
+ return biomeBytes->getValue()[z*SIZE + x];
else
- return (v[i/2] & 0xf);
+ return biomeInts->getValue(z*SIZE + x);
}
- 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);
- }
-
- uint8_t getBiomeAt(size_t x, size_t z) const {
- return biomes[z*SIZE + x];
- }
+ bool getBlock(Block *block, const Section *section, size_t x, size_t y, size_t z, uint8_t prev_light) const;
public:
Chunk(const ChunkData *data);
@@ -107,11 +72,15 @@ public:
return *level;
}
- const NBT::ListTag & getSections() const {
- return *sections;
+ const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const {
+ size_t Y = y / SIZE;
+
+ if (Y >= sections.size() || !sections[Y])
+ return nullptr;
+
+ return sections[Y]->getBlockStateAt(x, y % SIZE, z);
}
- Block getBlock(size_t x, size_t y, size_t z) const;
Blocks getTopLayer() const;
};
diff --git a/src/World/Section.cpp b/src/World/Section.cpp
new file mode 100644
index 0000000..6f06435
--- /dev/null
+++ b/src/World/Section.cpp
@@ -0,0 +1,56 @@
+/*
+ Copyright (c) 2015-2018, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "Section.hpp"
+#include "../NBT/ByteTag.hpp"
+#include "../Util.hpp"
+
+
+namespace MinedMap {
+namespace World {
+
+Section::Section(const std::shared_ptr<const NBT::CompoundTag> &section) {
+ Y = assertValue(section->get<NBT::ByteTag>("Y"))->getValue();
+ blockLight = section->get<NBT::ByteArrayTag>("BlockLight");
+}
+
+
+std::unique_ptr<Section> Section::makeSection(const std::shared_ptr<const NBT::CompoundTag> &section) {
+ 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"));
+
+ return std::unique_ptr<Section>(new LegacySection(section, std::move(blocks), std::move(data)));
+}
+
+const Resource::BlockType * LegacySection::getBlockStateAt(size_t x, size_t y, size_t z) const {
+ uint8_t type = getBlockAt(x, y, z);
+ uint8_t data = getDataAt(x, y, z);
+
+ return Resource::LEGACY_BLOCK_TYPES.types[type][data];
+}
+
+}
+}
diff --git a/src/World/Section.hpp b/src/World/Section.hpp
new file mode 100644
index 0000000..a4686e3
--- /dev/null
+++ b/src/World/Section.hpp
@@ -0,0 +1,110 @@
+/*
+ Copyright (c) 2015-2018, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#pragma once
+
+
+#include "../NBT/ByteArrayTag.hpp"
+#include "../NBT/CompoundTag.hpp"
+#include "../Resource/BlockType.hpp"
+
+#include <cstdint>
+#include <stdexcept>
+
+
+namespace MinedMap {
+namespace World {
+
+class Section {
+public:
+ static const size_t SIZE = 16;
+
+private:
+ size_t Y;
+ std::shared_ptr<const NBT::ByteArrayTag> blockLight;
+
+protected:
+ 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;
+ }
+
+ static uint8_t getHalf(const uint8_t *v, size_t x, size_t y, size_t z) {
+ size_t i = getIndex(x, y, z);
+
+ if (i % 2)
+ return (v[i/2] >> 4);
+ else
+ return (v[i/2] & 0xf);
+ }
+
+ Section(const std::shared_ptr<const NBT::CompoundTag> &section);
+
+public:
+ virtual ~Section() {}
+
+ size_t getY() const { return Y; };
+
+ virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const = 0;
+
+ uint8_t getBlockLightAt(size_t x, size_t y, size_t z) const {
+ if (!blockLight)
+ return 0;
+
+ return getHalf(blockLight->getValue(), x, y, z);
+ }
+
+ static std::unique_ptr<Section> makeSection(const std::shared_ptr<const NBT::CompoundTag> &section);
+};
+
+class LegacySection : public Section {
+private:
+ std::shared_ptr<const NBT::ByteArrayTag> blocks;
+ std::shared_ptr<const NBT::ByteArrayTag> data;
+
+
+ uint8_t getBlockAt(size_t x, size_t y, size_t z) const {
+ return blocks->getValue()[getIndex(x, y, z)];
+ }
+
+ uint8_t getDataAt(size_t x, size_t y, size_t z) const {
+ return getHalf(data->getValue(), x, y, z);
+ }
+
+public:
+ LegacySection(
+ const std::shared_ptr<const NBT::CompoundTag> &section,
+ std::shared_ptr<const NBT::ByteArrayTag> &&blocks0,
+ std::shared_ptr<const NBT::ByteArrayTag> &&data0
+ ) : Section(section), blocks(blocks0), data(data0) {}
+
+ virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const;
+};
+
+}
+}