Fix compatibility of MapBlock decoding

also properly drop support for version < 22, which hasn't worked in years
This commit is contained in:
sfan5 2020-05-06 22:31:50 +02:00
parent 92f6b051a5
commit 2979dc5b6b
2 changed files with 27 additions and 16 deletions

@ -11,20 +11,18 @@ static inline uint16_t readU16(const unsigned char *data)
return data[0] << 8 | data[1]; return data[0] << 8 | data[1];
} }
static int readBlockContent(const unsigned char *mapData, u8 version, unsigned int datapos) static int readBlockContent(const unsigned char *mapData, u8 contentWidth, unsigned int datapos)
{ {
if (version >= 24) { if (contentWidth == 2) {
size_t index = datapos << 1; size_t index = datapos << 1;
return (mapData[index] << 8) | mapData[index + 1]; return (mapData[index] << 8) | mapData[index + 1];
} else if (version >= 20) { } else {
if (mapData[datapos] <= 0x80) u8 param = mapData[datapos];
return mapData[datapos]; if (param <= 0x7f)
return param;
else else
return (int(mapData[datapos]) << 4) | (int(mapData[datapos + 0x2000]) >> 4); return (int(param) << 4) | (int(mapData[datapos + 0x2000]) >> 4);
} }
std::ostringstream oss;
oss << "Unsupported map version " << version;
throw std::runtime_error(oss.str());
} }
BlockDecoder::BlockDecoder() BlockDecoder::BlockDecoder()
@ -39,6 +37,7 @@ void BlockDecoder::reset()
m_nameMap.clear(); m_nameMap.clear();
m_version = 0; m_version = 0;
m_contentWidth = 0;
m_mapData = ustring(); m_mapData = ustring();
} }
@ -50,16 +49,30 @@ void BlockDecoder::decode(const ustring &datastr)
uint8_t version = data[0]; uint8_t version = data[0];
//uint8_t flags = data[1]; //uint8_t flags = data[1];
if (version < 22) {
std::ostringstream oss;
oss << "Unsupported map version " << (int)version;
throw std::runtime_error(oss.str());
}
m_version = version; m_version = version;
size_t dataOffset = 0; size_t dataOffset = 0;
if (version >= 27) if (version >= 27)
dataOffset = 6;
else if (version >= 22)
dataOffset = 4; dataOffset = 4;
else else
dataOffset = 2; dataOffset = 2;
uint8_t contentWidth = data[dataOffset];
dataOffset++;
uint8_t paramsWidth = data[dataOffset];
dataOffset++;
if (contentWidth != 1 && contentWidth != 2)
throw std::runtime_error("unsupported map version (contentWidth)");
if (paramsWidth != 2)
throw std::runtime_error("unsupported map version (paramsWidth)");
m_contentWidth = contentWidth;
ZlibDecompressor decompressor(data, length); ZlibDecompressor decompressor(data, length);
decompressor.setSeekPos(dataOffset); decompressor.setSeekPos(dataOffset);
m_mapData = decompressor.decompress(); m_mapData = decompressor.decompress();
@ -67,8 +80,6 @@ void BlockDecoder::decode(const ustring &datastr)
dataOffset = decompressor.seekPos(); dataOffset = decompressor.seekPos();
// Skip unused data // Skip unused data
if (version <= 21)
dataOffset += 2;
if (version == 23) if (version == 23)
dataOffset += 1; dataOffset += 1;
if (version == 24) { if (version == 24) {
@ -92,7 +103,7 @@ void BlockDecoder::decode(const ustring &datastr)
dataOffset += 4; // Skip timestamp dataOffset += 4; // Skip timestamp
// Read mapping // Read mapping
if (version >= 22) { {
dataOffset++; // mapping version dataOffset++; // mapping version
uint16_t numMappings = readU16(data + dataOffset); uint16_t numMappings = readU16(data + dataOffset);
dataOffset += 2; dataOffset += 2;
@ -130,7 +141,7 @@ bool BlockDecoder::isEmpty() const
std::string BlockDecoder::getNode(u8 x, u8 y, u8 z) const std::string BlockDecoder::getNode(u8 x, u8 y, u8 z) const
{ {
unsigned int position = x + (y << 4) + (z << 8); unsigned int position = x + (y << 4) + (z << 8);
int content = readBlockContent(m_mapData.c_str(), m_version, position); int content = readBlockContent(m_mapData.c_str(), m_contentWidth, position);
if (content == m_blockAirId || content == m_blockIgnoreId) if (content == m_blockAirId || content == m_blockIgnoreId)
return ""; return "";
NameMap::const_iterator it = m_nameMap.find(content); NameMap::const_iterator it = m_nameMap.find(content);

@ -20,7 +20,7 @@ private:
int m_blockAirId; int m_blockAirId;
int m_blockIgnoreId; int m_blockIgnoreId;
u8 m_version; u8 m_version, m_contentWidth;
ustring m_mapData; ustring m_mapData;
}; };