Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Refactoring (2)
  • Loading branch information
sfan5 committed Mar 25, 2018
1 parent 2ebc3af commit 2f78c39
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 121 deletions.
142 changes: 142 additions & 0 deletions BlockDecoder.cpp
@@ -0,0 +1,142 @@
#include <stdint.h>
#include <string>
#include <iostream>
#include <sstream>

#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<const char *>(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;
}
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -173,6 +173,7 @@ configure_file(
add_definitions ( -DUSE_CMAKE_CONFIG_H )

set(mapper_SRCS
BlockDecoder.cpp
PixelAttributes.cpp
PlayerAttributes.cpp
TileGenerator.cpp
Expand Down
127 changes: 12 additions & 115 deletions TileGenerator.cpp
@@ -1,16 +1,16 @@
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <cstring>
#include <vector>

#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
Expand All @@ -25,11 +25,6 @@

using namespace std;

static inline uint16_t readU16(const unsigned char *data)
{
return data[0] << 8 | data[1];
}

template<typename T>
static inline T mymax(T a, T b)
{
Expand All @@ -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);
Expand Down Expand Up @@ -373,6 +352,7 @@ void TileGenerator::createImage()

void TileGenerator::renderMap()
{
BlockDecoder blk;
std::list<int> zlist = getZValueList();
for (std::list<int>::iterator zPosition = zlist.begin(); zPosition != zlist.end(); ++zPosition) {
int zPos = *zPosition;
Expand All @@ -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<const char *>(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) {
Expand All @@ -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) {
Expand All @@ -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();
Expand Down
35 changes: 35 additions & 0 deletions include/BlockDecoder.h
@@ -0,0 +1,35 @@
#ifndef BLOCKDECODER_H
#define BLOCKDECODER_H

#if __cplusplus >= 201103L
#include <unordered_map>
#else
#include <map>
#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<int, std::string> NameMap;
#else
typedef std::map<int, std::string> NameMap;
#endif
NameMap m_nameMap;
int m_blockAirId;
int m_blockIgnoreId;

u8 m_version;
ustring m_mapData;
};

#endif // BLOCKDECODER_H

0 comments on commit 2f78c39

Please sign in to comment.