From c082c8800c42d6f9da98ed985babc8ad2c2265a7 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 20 Jul 2018 23:33:11 +0200 Subject: Separate splitting of regions into chunks and actual parsing of chunk structure --- src/CMakeLists.txt | 1 + src/MinedMap.cpp | 7 ++-- src/World/Chunk.cpp | 63 ++------------------------------ src/World/Chunk.hpp | 17 ++------- src/World/ChunkData.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ src/World/ChunkData.hpp | 60 ++++++++++++++++++++++++++++++ src/World/Region.cpp | 2 +- src/World/Region.hpp | 2 +- 8 files changed, 170 insertions(+), 79 deletions(-) create mode 100644 src/World/ChunkData.cpp create mode 100644 src/World/ChunkData.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 57bd303..070d419 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(MinedMap Resource/BlockType.cpp World/Block.cpp World/Chunk.cpp + World/ChunkData.cpp World/Level.cpp World/Region.cpp ) diff --git a/src/MinedMap.cpp b/src/MinedMap.cpp index 3fd9d94..bfd34b9 100644 --- a/src/MinedMap.cpp +++ b/src/MinedMap.cpp @@ -52,8 +52,9 @@ namespace MinedMap { static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE; -static void addChunk(uint32_t image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z, const World::Chunk *chunk) { - World::Chunk::Blocks layer = chunk->getTopLayer(); +static void addChunk(uint32_t image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z, const World::ChunkData *data) { + World::Chunk chunk(data); + World::Chunk::Blocks layer = chunk.getTopLayer(); for (size_t x = 0; x < World::Chunk::SIZE; x++) { for (size_t z = 0; z < World::Chunk::SIZE; z++) { @@ -139,7 +140,7 @@ static void doRegion(const std::string &input, const std::string &output, const std::unique_ptr lightmap(new uint8_t[2*DIM*DIM]); std::memset(lightmap.get(), 0, 2*DIM*DIM); - World::Region::visitChunks(input.c_str(), [&] (size_t X, size_t Z, const World::Chunk *chunk) { addChunk(image.get(), lightmap.get(), X, Z, chunk); }); + World::Region::visitChunks(input.c_str(), [&] (size_t X, size_t Z, const World::ChunkData *chunk) { addChunk(image.get(), lightmap.get(), X, Z, chunk); }); writeImage(output, reinterpret_cast(image.get()), true, intime); writeImage(output_light, lightmap.get(), false, intime); diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp index bf59068..07e38a4 100644 --- a/src/World/Chunk.cpp +++ b/src/World/Chunk.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015, Matthias Schiffer + Copyright (c) 2015-2018, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without @@ -38,66 +38,9 @@ namespace MinedMap { namespace World { -Chunk::Chunk(Buffer buffer) { - size_t size = buffer.get32(); +Chunk::Chunk(const ChunkData *data) { + level = assertValue(data->getRoot().get("Level")); - Buffer buffer2(buffer.get(size), size); - - uint8_t format = buffer2.get8(); - if (format != 2) - throw std::invalid_argument("unknown chunk format"); - - inflateChunk(buffer2); - parseChunk(); - analyzeChunk(); -} - -void Chunk::inflateChunk(Buffer buffer) { - size_t outlen = 0; - uint8_t *output = nullptr; - - z_stream stream = {}; - int ret = inflateInit(&stream); - if (ret != Z_OK) - throw std::runtime_error("inflateInit() failed"); - - stream.avail_in = buffer.getRemaining(); - stream.next_in = const_cast(buffer.get(stream.avail_in)); - - while (stream.avail_in) { - outlen += 65536; - output = static_cast(std::realloc(output, outlen)); - - stream.next_out = output + stream.total_out; - stream.avail_out = outlen - stream.total_out; - - ret = inflate(&stream, Z_NO_FLUSH); - switch (ret) { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&stream); - throw std::runtime_error("inflate() failed"); - } - } - - inflateEnd(&stream); - - len = stream.total_out; - data = UniqueCPtr(output); -} - -void Chunk::parseChunk() { - Buffer nbt(data.get(), len); - std::pair> tag = NBT::Tag::readNamedTag(&nbt); - if (tag.first != "") - throw std::invalid_argument("invalid root tag"); - - root = assertValue(std::dynamic_pointer_cast(tag.second)); - level = assertValue(root->get("Level")); -} - -void Chunk::analyzeChunk() { std::shared_ptr lightPopulatedTag = level->get("LightPopulated"); bool lightPopulated = lightPopulatedTag && lightPopulatedTag->getValue(); diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp index a08f9e6..d4213b3 100644 --- a/src/World/Chunk.hpp +++ b/src/World/Chunk.hpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2015, Matthias Schiffer + Copyright (c) 2015-2018, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without @@ -28,10 +28,8 @@ #include "Block.hpp" -#include "../Buffer.hpp" -#include "../UniqueCPtr.hpp" +#include "ChunkData.hpp" #include "../Util.hpp" -#include "../NBT/CompoundTag.hpp" #include "../NBT/ListTag.hpp" #include "../NBT/ByteTag.hpp" #include "../NBT/ByteArrayTag.hpp" @@ -53,10 +51,6 @@ public: private: - size_t len; - UniqueCPtr data; - - std::shared_ptr root; std::shared_ptr level; std::shared_ptr> sections; @@ -106,13 +100,8 @@ private: return biomes[z*SIZE + x]; } - - void inflateChunk(Buffer buffer); - void parseChunk(); - void analyzeChunk(); - public: - Chunk(Buffer buffer); + Chunk(const ChunkData *data); const NBT::CompoundTag & getLevel() const { return *level; diff --git a/src/World/ChunkData.cpp b/src/World/ChunkData.cpp new file mode 100644 index 0000000..7eb8ea4 --- /dev/null +++ b/src/World/ChunkData.cpp @@ -0,0 +1,97 @@ +/* + Copyright (c) 2015-2018, Matthias Schiffer + 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 "ChunkData.hpp" + +#include +#include +#include + +#include + + +namespace MinedMap { +namespace World { + +ChunkData::ChunkData(Buffer buffer) { + size_t size = buffer.get32(); + + Buffer buffer2(buffer.get(size), size); + + uint8_t format = buffer2.get8(); + if (format != 2) + throw std::invalid_argument("unknown chunk format"); + + inflateChunk(buffer2); + parseChunk(); +} + +void ChunkData::inflateChunk(Buffer buffer) { + size_t outlen = 0; + uint8_t *output = nullptr; + + z_stream stream = {}; + int ret = inflateInit(&stream); + if (ret != Z_OK) + throw std::runtime_error("inflateInit() failed"); + + stream.avail_in = buffer.getRemaining(); + stream.next_in = const_cast(buffer.get(stream.avail_in)); + + while (stream.avail_in) { + outlen += 65536; + output = static_cast(std::realloc(output, outlen)); + + stream.next_out = output + stream.total_out; + stream.avail_out = outlen - stream.total_out; + + ret = inflate(&stream, Z_NO_FLUSH); + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&stream); + throw std::runtime_error("inflate() failed"); + } + } + + inflateEnd(&stream); + + len = stream.total_out; + data = UniqueCPtr(output); +} + +void ChunkData::parseChunk() { + Buffer nbt(data.get(), len); + std::pair> tag = NBT::Tag::readNamedTag(&nbt); + if (tag.first != "") + throw std::invalid_argument("invalid root tag"); + + root = assertValue(std::dynamic_pointer_cast(tag.second)); +} + +} +} diff --git a/src/World/ChunkData.hpp b/src/World/ChunkData.hpp new file mode 100644 index 0000000..5fe27c9 --- /dev/null +++ b/src/World/ChunkData.hpp @@ -0,0 +1,60 @@ +/* + Copyright (c) 2015-2018, Matthias Schiffer + 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 "../Buffer.hpp" +#include "../UniqueCPtr.hpp" +#include "../Util.hpp" +#include "../NBT/CompoundTag.hpp" + +#include + + +namespace MinedMap { +namespace World { + +class ChunkData { +private: + size_t len; + UniqueCPtr data; + + std::shared_ptr root; + + void inflateChunk(Buffer buffer); + void parseChunk(); + +public: + ChunkData(Buffer buffer); + + const NBT::CompoundTag & getRoot() const { + return *root; + } +}; + +} +} diff --git a/src/World/Region.cpp b/src/World/Region.cpp index 886f96b..830256e 100644 --- a/src/World/Region.cpp +++ b/src/World/Region.cpp @@ -91,7 +91,7 @@ void Region::visitChunks(const char *filename, const ChunkVisitor &visitor) { uint8_t buffer[len * 4096]; file.read((char *)buffer, len * 4096); - Chunk chunk(Buffer(buffer, len * 4096)); + ChunkData chunk(Buffer(buffer, len * 4096)); visitor(x, z, &chunk); i += len; diff --git a/src/World/Region.hpp b/src/World/Region.hpp index 7a8088f..00bfd7b 100644 --- a/src/World/Region.hpp +++ b/src/World/Region.hpp @@ -42,7 +42,7 @@ class Region { public: static const size_t SIZE = 32; - typedef std::function ChunkVisitor; + typedef std::function ChunkVisitor; Region() = delete; -- cgit v1.2.3