Add partial node metadata decoding to BlockDecoder.

Reads the key/value node metadata strings, but skips the inventories (for now).
master^2
Martijn Versteegh 2018-11-18 21:12:26 +01:00 committed by Martijn Versteegh
parent 8e1279ffdf
commit ec14c0e2f6
2 changed files with 114 additions and 8 deletions

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include <string.h>
#include <string>
#include <iostream>
#include <sstream>
@ -11,6 +12,12 @@ static inline uint16_t readU16(const unsigned char *data)
return data[0] << 8 | data[1];
}
static inline uint32_t readU32(const unsigned char *data)
{
return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
}
static int readBlockContent(const unsigned char *mapData, u8 version, unsigned int datapos)
{
if (version >= 24) {
@ -27,7 +34,8 @@ static int readBlockContent(const unsigned char *mapData, u8 version, unsigned i
throw std::runtime_error(oss.str());
}
BlockDecoder::BlockDecoder()
BlockDecoder::BlockDecoder(bool withMetaData)
: m_withMetaData(withMetaData)
{
reset();
}
@ -38,6 +46,7 @@ void BlockDecoder::reset()
m_blockIgnoreId = -1;
m_nameMap.clear();
m_metaData.clear();
m_version = 0;
m_mapData = ustring();
}
@ -63,9 +72,74 @@ void BlockDecoder::decode(const ustring &datastr)
ZlibDecompressor decompressor(data, length);
decompressor.setSeekPos(dataOffset);
m_mapData = decompressor.decompress();
decompressor.decompress(); // unused metadata
ustring metaData = decompressor.decompress(); // unused metadata
dataOffset = decompressor.seekPos();
if (m_withMetaData && version >= 27)
{
unsigned char const *md = metaData.c_str();
unsigned char const *metaDataEnd = md + metaData.size();
int metaDataVersion = md[0];
md++;
if (metaDataVersion)
{
int metaDataCount = readU16(md);
md+=2;
for (int i = 0; i < metaDataCount ; i++)
{
int position = readU16(md);
md+=2;
unsigned int numVars = readU32(md);
md+=4;
NodeMetaData nmd;
for (unsigned var = 0; var < numVars; var++)
{
size_t keyLen = readU16(md);
md+=2;
std::string key((char const *)md, keyLen);
md+= keyLen;
size_t valueLen = readU32(md);
md+=4;
std::string value((char const *)md, valueLen);
nmd.push_back(std::pair<std::string, std::string>(key, value));
md+= valueLen;
if (metaDataVersion > 1)
{
md++; // skip priv flag
}
}
m_metaData[position] = nmd;
if (md < metaDataEnd && !strncmp("List", reinterpret_cast<const char *>(md), 4)) // skip inventory for now
{
while (true)
{
unsigned char const *start = md;
while (*md != '\n')
{
md++;
if (md >= metaDataEnd)
{
std::cout << "Invalid metadata in Block!";
//! thrown runtime error
}
}
md++;
if (!strncmp("EndInventory", reinterpret_cast<char const *>(start), 12))
{
break;
}
}
}
}
}
}
// Skip unused data
if (version <= 21)
dataOffset += 2;
@ -140,3 +214,22 @@ std::string BlockDecoder::getNode(u8 x, u8 y, u8 z) const
}
return it->second;
}
BlockDecoder::NodeMetaData const &BlockDecoder::getNodeMetaData(u8 x, u8 y, u8 z) const
{
unsigned int position = x + (y << 4) + (z << 8);
MetaData::const_iterator m = m_metaData.find(position);
if (m == m_metaData.end())
{
return s_emptyMetaData;
}
return m->second;
}
BlockDecoder::NodeMetaData BlockDecoder::s_emptyMetaData;

View File

@ -7,27 +7,40 @@
#include <map>
#endif
#include <vector>
#include "types.h"
class BlockDecoder {
public:
BlockDecoder();
typedef std::vector<std::pair<std::string, std::string>> NodeMetaData;
#if __cplusplus >= 201103L
typedef std::unordered_map<int, NodeMetaData> MetaData;
typedef std::unordered_map<int, std::string> NameMap;
#else
typedef std::map<int, NodeMetaData> MetaData;
typedef std::map<int, std::string> NameMap;
#endif
BlockDecoder(bool withMetaData = false);
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
NodeMetaData const &getNodeMetaData(u8 x, u8 y, u8 z) const;
private:
#if __cplusplus >= 201103L
typedef std::unordered_map<int, std::string> NameMap;
#else
typedef std::map<int, std::string> NameMap;
#endif
static NodeMetaData s_emptyMetaData;
NameMap m_nameMap;
MetaData m_metaData;
int m_blockAirId;
int m_blockIgnoreId;
bool m_withMetaData;
u8 m_version;
ustring m_mapData;
};