From 2f78c39d9c64e60d1655952a2f45767a197ca2a5 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 25 Mar 2018 15:19:48 +0200 Subject: [PATCH] Refactoring (2) --- BlockDecoder.cpp | 142 ++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + TileGenerator.cpp | 127 ++++------------------------------- include/BlockDecoder.h | 35 ++++++++++ include/TileGenerator.h | 9 +-- 5 files changed, 193 insertions(+), 121 deletions(-) create mode 100644 BlockDecoder.cpp create mode 100644 include/BlockDecoder.h diff --git a/BlockDecoder.cpp b/BlockDecoder.cpp new file mode 100644 index 0000000..3b6c5b1 --- /dev/null +++ b/BlockDecoder.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include + +#include "BlockDecoder.h" +#include "ZlibDecompressor.h" + +static inline uint16_t readU16(const unsigned char *data) +{ + return data[0] << 8 | data[1]; +} + +static int readBlockContent(const unsigned char *mapData, u8 version, unsigned int datapos) +{ + if (version >= 24) { + size_t index = datapos << 1; + return (mapData[index] << 8) | mapData[index + 1]; + } else if (version >= 20) { + if (mapData[datapos] <= 0x80) + return mapData[datapos]; + else + return (int(mapData[datapos]) << 4) | (int(mapData[datapos + 0x2000]) >> 4); + } + std::ostringstream oss; + oss << "Unsupported map version " << version; + throw std::runtime_error(oss.str()); +} + +BlockDecoder::BlockDecoder() +{ + reset(); +} + +void BlockDecoder::reset() +{ + m_blockAirId = -1; + m_blockIgnoreId = -1; + m_nameMap.clear(); + + m_version = 0; + m_mapData = ustring(); +} + +void BlockDecoder::decode(const ustring &datastr) +{ + const unsigned char *data = datastr.c_str(); + size_t length = datastr.length(); + // TODO: bounds checks + + uint8_t version = data[0]; + //uint8_t flags = data[1]; + m_version = version; + + size_t dataOffset = 0; + if (version >= 27) + dataOffset = 6; + else if (version >= 22) + dataOffset = 4; + else + dataOffset = 2; + + ZlibDecompressor decompressor(data, length); + decompressor.setSeekPos(dataOffset); + m_mapData = decompressor.decompress(); + decompressor.decompress(); // unused metadata + dataOffset = decompressor.seekPos(); + + // Skip unused data + if (version <= 21) + dataOffset += 2; + if (version == 23) + dataOffset += 1; + if (version == 24) { + uint8_t ver = data[dataOffset++]; + if (ver == 1) { + uint16_t num = readU16(data + dataOffset); + dataOffset += 2; + dataOffset += 10 * num; + } + } + + // Skip unused static objects + dataOffset++; // Skip static object version + int staticObjectCount = readU16(data + dataOffset); + dataOffset += 2; + for (int i = 0; i < staticObjectCount; ++i) { + dataOffset += 13; + uint16_t dataSize = readU16(data + dataOffset); + dataOffset += dataSize + 2; + } + dataOffset += 4; // Skip timestamp + + // Read mapping + if (version >= 22) { + dataOffset++; // mapping version + uint16_t numMappings = readU16(data + dataOffset); + dataOffset += 2; + for (int i = 0; i < numMappings; ++i) { + uint16_t nodeId = readU16(data + dataOffset); + dataOffset += 2; + uint16_t nameLen = readU16(data + dataOffset); + dataOffset += 2; + std::string name(reinterpret_cast(data) + dataOffset, nameLen); + if (name == "air") + m_blockAirId = nodeId; + else if (name == "ignore") + m_blockIgnoreId = nodeId; + else + m_nameMap[nodeId] = name; + dataOffset += nameLen; + } + } + + // Node timers + if (version >= 25) { + dataOffset++; + uint16_t numTimers = readU16(data + dataOffset); + dataOffset += 2; + dataOffset += numTimers * 10; + } +} + +bool BlockDecoder::isEmpty() const +{ + // only contains ignore and air nodes? + return m_nameMap.empty(); +} + +std::string BlockDecoder::getNode(u8 x, u8 y, u8 z) const +{ + unsigned int position = x + (y << 4) + (z << 8); + int content = readBlockContent(m_mapData.c_str(), m_version, position); + if (content == m_blockAirId || content == m_blockIgnoreId) + return ""; + NameMap::const_iterator it = m_nameMap.find(content); + if (it == m_nameMap.end()) { + std::cerr << "Skipping node with invalid ID." << std::endl; + return ""; + } + return it->second; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index dd164a9..8732b85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,7 @@ configure_file( add_definitions ( -DUSE_CMAKE_CONFIG_H ) set(mapper_SRCS + BlockDecoder.cpp PixelAttributes.cpp PlayerAttributes.cpp TileGenerator.cpp diff --git a/TileGenerator.cpp b/TileGenerator.cpp index 4369af3..010b0b6 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -7,10 +6,11 @@ #include #include #include + +#include "TileGenerator.h" #include "config.h" #include "PlayerAttributes.h" -#include "TileGenerator.h" -#include "ZlibDecompressor.h" +#include "BlockDecoder.h" #include "util.h" #include "db-sqlite3.h" #if USE_POSTGRESQL @@ -25,11 +25,6 @@ using namespace std; -static inline uint16_t readU16(const unsigned char *data) -{ - return data[0] << 8 | data[1]; -} - template static inline T mymax(T a, T b) { @@ -54,22 +49,6 @@ static int round_multiple_nosign(int n, int f) return sign * (abs_n + f - (abs_n % f)); } -static int readBlockContent(const unsigned char *mapData, int version, int datapos) -{ - if (version >= 24) { - size_t index = datapos << 1; - return (mapData[index] << 8) | mapData[index + 1]; - } else if (version >= 20) { - if (mapData[datapos] <= 0x80) - return mapData[datapos]; - else - return (int(mapData[datapos]) << 4) | (int(mapData[datapos + 0x2000]) >> 4); - } - std::ostringstream oss; - oss << "Unsupported map version " << version; - throw std::runtime_error(oss.str()); -} - static inline unsigned int colorSafeBounds (int channel) { return mymin(mymax(channel, 0), 255); @@ -373,6 +352,7 @@ void TileGenerator::createImage() void TileGenerator::renderMap() { + BlockDecoder blk; std::list zlist = getZValueList(); for (std::list::iterator zPosition = zlist.begin(); zPosition != zlist.end(); ++zPosition) { int zPos = *zPosition; @@ -399,87 +379,12 @@ void TileGenerator::renderMap() const BlockList &blockStack = blocks[xPos]; for (BlockList::const_iterator it = blockStack.begin(); it != blockStack.end(); ++it) { const BlockPos &pos = it->first; - const unsigned char *data = it->second.c_str(); - size_t length = it->second.length(); - uint8_t version = data[0]; - //uint8_t flags = data[1]; - - size_t dataOffset = 0; - if (version >= 27) - dataOffset = 6; - else if (version >= 22) - dataOffset = 4; - else - dataOffset = 2; - - ZlibDecompressor decompressor(data, length); - decompressor.setSeekPos(dataOffset); - ustring mapData = decompressor.decompress(); - ustring mapMetadata = decompressor.decompress(); - dataOffset = decompressor.seekPos(); - - // Skip unused data - if (version <= 21) - dataOffset += 2; - if (version == 23) - dataOffset += 1; - if (version == 24) { - uint8_t ver = data[dataOffset++]; - if (ver == 1) { - uint16_t num = readU16(data + dataOffset); - dataOffset += 2; - dataOffset += 10 * num; - } - } - - // Skip unused static objects - dataOffset++; // Skip static object version - int staticObjectCount = readU16(data + dataOffset); - dataOffset += 2; - for (int i = 0; i < staticObjectCount; ++i) { - dataOffset += 13; - uint16_t dataSize = readU16(data + dataOffset); - dataOffset += dataSize + 2; - } - dataOffset += 4; // Skip timestamp - - m_blockAirId = -1; - m_blockIgnoreId = -1; - m_nameMap.clear(); - // Read mapping - if (version >= 22) { - dataOffset++; // mapping version - uint16_t numMappings = readU16(data + dataOffset); - dataOffset += 2; - for (int i = 0; i < numMappings; ++i) { - uint16_t nodeId = readU16(data + dataOffset); - dataOffset += 2; - uint16_t nameLen = readU16(data + dataOffset); - dataOffset += 2; - string name = string(reinterpret_cast(data) + dataOffset, nameLen); - if (name == "air") - m_blockAirId = nodeId; - else if (name == "ignore") - m_blockIgnoreId = nodeId; - else - m_nameMap[nodeId] = name; - dataOffset += nameLen; - } - // Skip block if made of only air or ignore nodes - if (m_nameMap.empty()) - continue; - } - - // Node timers - if (version >= 25) { - dataOffset++; - uint16_t numTimers = readU16(data + dataOffset); - dataOffset += 2; - dataOffset += numTimers * 10; - } - - renderMapBlock(mapData, pos, version); + blk.reset(); + blk.decode(it->second); + if (blk.isEmpty()) + continue; + renderMapBlock(blk, pos); bool allRead = true; for (int i = 0; i < 16; ++i) { @@ -502,11 +407,10 @@ void TileGenerator::renderMap() } } -void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int version) +void TileGenerator::renderMapBlock(const BlockDecoder &blk, const BlockPos &pos) { int xBegin = (pos.x - m_xMin) * 16; int zBegin = (m_zMax - pos.z) * 16; - const unsigned char *mapData = mapBlock.c_str(); int minY = (pos.y * 16 > m_yMin) ? 0 : m_yMin - pos.y * 16; int maxY = (pos.y * 16 < m_yMax) ? 15 : m_yMax - pos.y * 16; for (int z = 0; z < 16; ++z) { @@ -517,16 +421,9 @@ void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int imageX = xBegin + x; for (int y = maxY; y >= minY; --y) { - int position = x + (y << 4) + (z << 8); - int content = readBlockContent(mapData, version, position); - if (content == m_blockAirId || content == m_blockIgnoreId) + string name = blk.getNode(x, y, z); + if (name == "") continue; - NameMap::iterator blockName = m_nameMap.find(content); - if (blockName == m_nameMap.end()) { - std::cerr << "Skipping node with invalid ID." << std::endl; - continue; - } - const string &name = blockName->second; ColorMap::const_iterator color = m_colorMap.find(name); if (color != m_colorMap.end()) { const Color c = color->second.to_color(); diff --git a/include/BlockDecoder.h b/include/BlockDecoder.h new file mode 100644 index 0000000..ce69449 --- /dev/null +++ b/include/BlockDecoder.h @@ -0,0 +1,35 @@ +#ifndef BLOCKDECODER_H +#define BLOCKDECODER_H + +#if __cplusplus >= 201103L +#include +#else +#include +#endif + +#include "types.h" + +class BlockDecoder { +public: + BlockDecoder(); + + void reset(); + void decode(const ustring &data); + bool isEmpty() const; + std::string getNode(u8 x, u8 y, u8 z) const; // returns "" for air, ignore and invalid nodes + +private: +#if __cplusplus >= 201103L + typedef std::unordered_map NameMap; +#else + typedef std::map NameMap; +#endif + NameMap m_nameMap; + int m_blockAirId; + int m_blockIgnoreId; + + u8 m_version; + ustring m_mapData; +}; + +#endif // BLOCKDECODER_H diff --git a/include/TileGenerator.h b/include/TileGenerator.h index 4ed0cad..d07eba6 100644 --- a/include/TileGenerator.h +++ b/include/TileGenerator.h @@ -14,7 +14,9 @@ #endif #include #include + #include "PixelAttributes.h" +#include "BlockDecoder.h" #include "Image.h" #include "db.h" #include "types.h" @@ -43,11 +45,9 @@ class TileGenerator private: #if __cplusplus >= 201103L typedef std::unordered_map ColorMap; - typedef std::unordered_map NameMap; typedef std::unordered_set NameSet; #else typedef std::map ColorMap; - typedef std::map NameMap; typedef std::set NameSet; #endif @@ -80,7 +80,7 @@ private: void createImage(); void renderMap(); std::list getZValueList() const; - void renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int version); + void renderMapBlock(const BlockDecoder &blk, const BlockPos &pos); void renderMapBlockBottom(const BlockPos &pos); void renderShading(int zPos); void renderScale(); @@ -121,7 +121,6 @@ private: int m_mapWidth; int m_mapHeight; std::list > m_positions; - NameMap m_nameMap; ColorMap m_colorMap; uint16_t m_readPixels[16]; uint16_t m_readInfo[16]; @@ -129,8 +128,6 @@ private: Color m_color[16][16]; uint8_t m_thickness[16][16]; - int m_blockAirId; - int m_blockIgnoreId; int m_zoom; uint m_scales; }; // class TileGenerator