2 Commits

Author SHA1 Message Date
de259280b6 Fix travis 2016-12-05 12:43:41 +01:00
75009ad49c Initial work on using FreeImage 2016-12-05 12:40:27 +01:00
33 changed files with 739 additions and 1575 deletions

View File

@ -2,8 +2,23 @@ language: cpp
compiler:
- gcc
- clang
dist: bionic
before_install: sudo apt-get install -y cmake libgd-dev libsqlite3-dev libleveldb-dev
sudo: false
addons:
apt:
sources:
- llvm-toolchain-precise-3.8
- ubuntu-toolchain-r-test
packages:
- cmake
- libfreeimage-dev
- libsqlite3-dev
- p7zip
- g++-6
- clang-3.8
before_install:
- # Nothing ever works correctly with precise, use a custom libleveldb build
- wget http://minetest.kitsunemimi.pw/libleveldb-1.18-ubuntu12.04.7z
- 7zr x -olibleveldb libleveldb-1.18-ubuntu12.04.7z
script: ./util/travis/script.sh
notifications:
email: false

View File

@ -1,142 +0,0 @@
#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;
}

View File

@ -13,7 +13,7 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
endif()
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g2 -Wall")
if(WIN32)
@ -21,10 +21,9 @@ if(WIN32)
set(BINDIR ".")
set(DOCDIR ".")
else()
set(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share/minetest") # reuse Minetest share dir
set(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share/minetest") # an extra dir. for just one file doesn't seem useful
set(BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
set(DOCDIR "${CMAKE_INSTALL_PREFIX}/share/doc/${PROJECT_NAME}")
set(MANDIR "${CMAKE_INSTALL_PREFIX}/share/man")
endif()
set(CUSTOM_SHAREDIR "" CACHE STRING "Directory to install data files into")
@ -46,15 +45,15 @@ if(NOT CUSTOM_DOCDIR STREQUAL "")
endif()
# Libraries: gd
# Libraries: freeimage
find_library(LIBGD_LIBRARY gd)
find_path(LIBGD_INCLUDE_DIR gd.h)
message (STATUS "libgd library: ${LIBGD_LIBRARY}")
message (STATUS "libgd headers: ${LIBGD_INCLUDE_DIR}")
if(NOT LIBGD_LIBRARY OR NOT LIBGD_INCLUDE_DIR)
message(FATAL_ERROR "libgd not found!")
endif(NOT LIBGD_LIBRARY OR NOT LIBGD_INCLUDE_DIR)
find_library(FREEIMAGE_LIBRARY freeimage)
find_path(FREEIMAGE_INCLUDE_DIR FreeImage.h)
message (STATUS "FreeImage library: ${FREEIMAGE_LIBRARY}")
message (STATUS "FreeImage headers: ${FREEIMAGE_INCLUDE_DIR}")
if(NOT FREEIMAGE_LIBRARY OR NOT FREEIMAGE_INCLUDE_DIR)
message(FATAL_ERROR "FreeImage not found!")
endif(NOT FREEIMAGE_LIBRARY OR NOT FREEIMAGE_INCLUDE_DIR)
# Libraries: zlib
@ -79,40 +78,6 @@ if(NOT SQLITE3_LIBRARY OR NOT SQLITE3_INCLUDE_DIR)
message(FATAL_ERROR "sqlite3 not found!")
endif(NOT SQLITE3_LIBRARY OR NOT SQLITE3_INCLUDE_DIR)
# Libraries: postgresql
option(ENABLE_POSTGRESQL "Enable PostgreSQL backend" TRUE)
set(USE_POSTGRESQL 0)
if(ENABLE_POSTGRESQL)
find_program(POSTGRESQL_CONFIG_EXECUTABLE pg_config DOC "pg_config")
find_library(POSTGRESQL_LIBRARY pq)
if(POSTGRESQL_CONFIG_EXECUTABLE)
execute_process(COMMAND ${POSTGRESQL_CONFIG_EXECUTABLE} --includedir-server
OUTPUT_VARIABLE POSTGRESQL_SERVER_INCLUDE_DIRS
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${POSTGRESQL_CONFIG_EXECUTABLE}
OUTPUT_VARIABLE POSTGRESQL_CLIENT_INCLUDE_DIRS
OUTPUT_STRIP_TRAILING_WHITESPACE)
# This variable is case sensitive for the cmake PostgreSQL module
set(PostgreSQL_ADDITIONAL_SEARCH_PATHS ${POSTGRESQL_SERVER_INCLUDE_DIRS} ${POSTGRESQL_CLIENT_INCLUDE_DIRS})
endif()
find_package("PostgreSQL")
if(POSTGRESQL_FOUND)
set(USE_POSTGRESQL 1)
message(STATUS "PostgreSQL backend enabled")
# This variable is case sensitive, don't try to change it to POSTGRESQL_INCLUDE_DIR
message(STATUS "PostgreSQL includes: ${PostgreSQL_INCLUDE_DIR}")
include_directories(${PostgreSQL_INCLUDE_DIR})
set(POSTGRESQL_LIBRARY ${PostgreSQL_LIBRARIES})
else()
message(STATUS "PostgreSQL not found.")
set(POSTGRESQL_LIBRARY "")
endif()
endif(ENABLE_POSTGRESQL)
# Libraries: leveldb
set(USE_LEVELDB 0)
@ -159,21 +124,20 @@ endif(ENABLE_REDIS)
include_directories(
"${PROJECT_BINARY_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}"
${SQLITE3_INCLUDE_DIR}
${LIBGD_INCLUDE_DIR}
${FREEIMAGE_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
)
configure_file(
"${PROJECT_SOURCE_DIR}/include/cmake_config.h.in"
"${PROJECT_SOURCE_DIR}/cmake_config.h.in"
"${PROJECT_BINARY_DIR}/cmake_config.h"
)
add_definitions ( -DUSE_CMAKE_CONFIG_H )
set(mapper_SRCS
BlockDecoder.cpp
PixelAttributes.cpp
PlayerAttributes.cpp
TileGenerator.cpp
@ -184,10 +148,6 @@ set(mapper_SRCS
db-sqlite3.cpp
)
if(USE_POSTGRESQL)
set(mapper_SRCS ${mapper_SRCS} db-postgresql.cpp)
endif(USE_POSTGRESQL)
if(USE_LEVELDB)
set(mapper_SRCS ${mapper_SRCS} db-leveldb.cpp)
endif(USE_LEVELDB)
@ -203,10 +163,9 @@ add_executable(minetestmapper
target_link_libraries(
minetestmapper
${SQLITE3_LIBRARY}
${POSTGRESQL_LIBRARY}
${LEVELDB_LIBRARY}
${REDIS_LIBRARY}
${LIBGD_LIBRARY}
${FREEIMAGE_LIBRARY}
${ZLIB_LIBRARY}
)
@ -217,9 +176,6 @@ install(FILES "AUTHORS" DESTINATION "${DOCDIR}")
install(FILES "COPYING" DESTINATION "${DOCDIR}")
install(FILES "README.rst" DESTINATION "${DOCDIR}")
install(FILES "colors.txt" DESTINATION "${SHAREDIR}")
if(UNIX)
install(FILES "minetestmapper.6" DESTINATION "${MANDIR}/man6")
endif()
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Overview mapper for Minetest")
set(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})

View File

@ -4,121 +4,100 @@
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <gd.h>
#include <gdfontmb.h>
#include "Image.h"
#ifndef NDEBUG
#define SIZECHECK(x, y) check_bounds((x), (y), m_width, m_height)
#define SIZECHECK(x, y) do { \
if((x) < 0 || (x) >= m_width) \
throw std::out_of_range("sizecheck x"); \
if((y) < 0 || (y) >= m_height) \
throw std::out_of_range("sizecheck y"); \
} while(0)
#else
#define SIZECHECK(x, y) do {} while(0)
#endif
// ARGB but with inverted alpha
static inline int color2int(Color c)
static inline RGBQUAD color2rgbquad(Color c)
{
u8 a = (255 - c.a) * gdAlphaMax / 255;
return (a << 24) | (c.r << 16) | (c.g << 8) | c.b;
}
static inline Color int2color(int c)
{
Color c2;
u8 a;
c2.b = c & 0xff;
c2.g = (c >> 8) & 0xff;
c2.r = (c >> 16) & 0xff;
a = (c >> 24) & 0xff;
c2.a = 255 - (a*255 / gdAlphaMax);
RGBQUAD c2;
c2.rgbRed = c.r;
c2.rgbGreen = c.g;
c2.rgbBlue = c.b;
return c2;
}
static inline void check_bounds(int x, int y, int width, int height)
static inline Color rgbquad2color(RGBQUAD c)
{
if(x < 0 || x >= width) {
std::ostringstream oss;
oss << "Access outside image bounds (x), 0 < "
<< x << " < " << width << " is false.";
throw std::out_of_range(oss.str());
}
if(y < 0 || y >= height) {
std::ostringstream oss;
oss << "Access outside image bounds (y), 0 < "
<< y << " < " << height << " is false.";
throw std::out_of_range(oss.str());
}
return Color(c.rgbRed, c.rgbGreen, c.rgbBlue);
}
Image::Image(int width, int height) :
m_width(width), m_height(height), m_image(NULL)
{
m_image = gdImageCreateTrueColor(m_width, m_height);
// FIXME: This works because minetestmapper only creates one image
FreeImage_Initialise();
printf("Using FreeImage v%s\n", FreeImage_GetVersion());
m_image = FreeImage_Allocate(width, height, 24);
}
Image::~Image()
{
gdImageDestroy(m_image);
FreeImage_Unload(m_image);
}
void Image::setPixel(int x, int y, const Color &c)
{
SIZECHECK(x, y);
m_image->tpixels[y][x] = color2int(c);
RGBQUAD col = color2rgbquad(c);
FreeImage_SetPixelColor(m_image, x, y, &col);
}
Color Image::getPixel(int x, int y)
{
SIZECHECK(x, y);
return int2color(m_image->tpixels[y][x]);
#ifndef NDEBUG
if(x < 0 || x > m_width || y < 0 || y > m_height)
throw std::out_of_range("sizecheck");
#endif
RGBQUAD c;
FreeImage_GetPixelColor(m_image, x, y, &c);
return rgbquad2color(c);
}
void Image::drawLine(int x1, int y1, int x2, int y2, const Color &c)
{
SIZECHECK(x1, y1);
SIZECHECK(x2, y2);
gdImageLine(m_image, x1, y1, x2, y2, color2int(c));
// TODO
}
void Image::drawText(int x, int y, const std::string &s, const Color &c)
{
SIZECHECK(x, y);
gdImageString(m_image, gdFontGetMediumBold(), x, y, (unsigned char*) s.c_str(), color2int(c));
// TODO
}
void Image::drawFilledRect(int x, int y, int w, int h, const Color &c)
{
SIZECHECK(x, y);
SIZECHECK(x + w - 1, y + h - 1);
gdImageFilledRectangle(m_image, x, y, x + w - 1, y + h - 1, color2int(c));
RGBQUAD col = color2rgbquad(c);
for(int xx = 0; xx < w; xx++)
for(int yy = 0; yy < h; yy++)
FreeImage_SetPixelColor(m_image, x + xx, y + yy, &col);
}
void Image::drawCircle(int x, int y, int diameter, const Color &c)
{
SIZECHECK(x, y);
gdImageArc(m_image, x, y, diameter, diameter, 0, 360, color2int(c));
// TODO
}
void Image::save(const std::string &filename)
{
#if (GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION == 1 && GD_RELEASE_VERSION >= 1) || (GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION > 1) || GD_MAJOR_VERSION > 2
const char *f = filename.c_str();
if (gdSupportsFileType(f, 1) == GD_FALSE)
throw std::runtime_error("Image format not supported by gd");
if (gdImageFile(m_image, f) == GD_FALSE)
throw std::runtime_error("Error saving image");
#else
if (filename.compare(filename.length() - 4, 4, ".png") != 0)
throw std::runtime_error("Only PNG is supported");
FILE *f = fopen(filename.c_str(), "wb");
if (!f) {
std::ostringstream oss;
oss << "Error opening image file: " << std::strerror(errno);
throw std::runtime_error(oss.str());
}
gdImagePng(m_image, f);
fclose(f);
#endif
FreeImage_Save(FIF_PNG, m_image, filename.c_str()); // other formats?
}

View File

@ -3,14 +3,12 @@
#include "types.h"
#include <string>
#include <gd.h>
#include <FreeImage.h>
struct Color {
Color() : r(0), g(0), b(0), a(0) {};
Color(u8 r, u8 g, u8 b) : r(r), g(g), b(b), a(255) {};
Color(u8 r, u8 g, u8 b, u8 a) : r(r), g(g), b(b), a(a) {};
inline Color noAlpha() const { return Color(r, g, b); }
u8 r, g, b, a;
};
@ -31,7 +29,7 @@ private:
Image(const Image&);
int m_width, m_height;
gdImagePtr m_image;
FIBITMAP *m_image;
};
#endif // IMAGE_HEADER

View File

@ -1,126 +1,66 @@
/*
* =====================================================================
* Version: 1.0
* Created: 01.09.2012 14:38:05
* Author: Miroslav Bendík
* Company: LinuxOS.sk
* =====================================================================
*/
#include <dirent.h>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <dirent.h>
#include <unistd.h> // for usleep
#include <sqlite3.h>
#include "config.h"
#include "PlayerAttributes.h"
#include "util.h"
using namespace std;
PlayerAttributes::PlayerAttributes(const std::string &worldDir)
PlayerAttributes::PlayerAttributes(const std::string &sourceDirectory)
{
std::ifstream ifs((worldDir + "world.mt").c_str());
if (!ifs.good())
throw std::runtime_error("Failed to read world.mt");
std::string backend = read_setting_default("player_backend", ifs, "files");
ifs.close();
if (backend == "files")
readFiles(worldDir + "players");
else if (backend == "sqlite3")
readSqlite(worldDir + "players.sqlite");
else
throw std::runtime_error(((std::string) "Unknown player backend: ") + backend);
}
void PlayerAttributes::readFiles(const std::string &playersPath)
{
string playersPath = sourceDirectory + "players";
DIR *dir;
dir = opendir (playersPath.c_str());
if (dir == NULL)
if (dir == NULL) {
return;
}
struct dirent *ent;
while ((ent = readdir (dir)) != NULL) {
if (ent->d_name[0] == '.')
if (ent->d_name[0] == '.') {
continue;
}
string path = playersPath + PATH_SEPARATOR + ent->d_name;
ifstream in(path.c_str());
if(!in.good())
continue;
string name, position;
name = read_setting("name", in);
in.seekg(0);
position = read_setting("position", in);
ifstream in;
in.open(path.c_str(), ifstream::in);
string buffer;
string name;
string position;
while (getline(in, buffer)) {
if (buffer.find("name = ") == 0) {
name = buffer.substr(7);
}
else if (buffer.find("position = ") == 0) {
position = buffer.substr(12, buffer.length() - 13);
}
}
char comma;
Player player;
istringstream iss(position);
char tmp;
iss >> tmp; // '('
iss >> player.x;
iss >> tmp; // ','
iss >> player.y;
iss >> tmp; // ','
iss >> player.z;
iss >> tmp; // ')'
if(tmp != ')')
continue;
istringstream positionStream(position, istringstream::in);
positionStream >> player.x;
positionStream >> comma;
positionStream >> player.y;
positionStream >> comma;
positionStream >> player.z;
player.name = name;
player.x /= 10.0;
player.y /= 10.0;
player.z /= 10.0;
m_players.push_back(player);
}
closedir(dir);
}
/**********/
#define SQLRES(f, good) \
result = (sqlite3_##f); \
if (result != good) { \
throw std::runtime_error(sqlite3_errmsg(db));\
}
#define SQLOK(f) SQLRES(f, SQLITE_OK)
void PlayerAttributes::readSqlite(const std::string &db_name)
{
int result;
sqlite3 *db;
sqlite3_stmt *stmt_get_player_pos;
SQLOK(open_v2(db_name.c_str(), &db, SQLITE_OPEN_READONLY |
SQLITE_OPEN_PRIVATECACHE, 0))
SQLOK(prepare_v2(db,
"SELECT name, posX, posY, posZ FROM player",
-1, &stmt_get_player_pos, NULL))
while ((result = sqlite3_step(stmt_get_player_pos)) != SQLITE_DONE) {
if (result == SQLITE_BUSY) { // Wait some time and try again
usleep(10000);
} else if (result != SQLITE_ROW) {
throw std::runtime_error(sqlite3_errmsg(db));
}
Player player;
const unsigned char *name_ = sqlite3_column_text(stmt_get_player_pos, 0);
player.name = std::string(reinterpret_cast<const char*>(name_));
player.x = sqlite3_column_double(stmt_get_player_pos, 1);
player.y = sqlite3_column_double(stmt_get_player_pos, 2);
player.z = sqlite3_column_double(stmt_get_player_pos, 3);
player.x /= 10.0;
player.y /= 10.0;
player.z /= 10.0;
m_players.push_back(player);
}
sqlite3_finalize(stmt_get_player_pos);
sqlite3_close(db);
}
/**********/
PlayerAttributes::Players::iterator PlayerAttributes::begin()
{
return m_players.begin();

38
PlayerAttributes.h Normal file
View File

@ -0,0 +1,38 @@
/*
* =====================================================================
* Version: 1.0
* Created: 01.09.2012 14:38:08
* Author: Miroslav Bendík
* Company: LinuxOS.sk
* =====================================================================
*/
#ifndef PLAYERATTRIBUTES_H_D7THWFVV
#define PLAYERATTRIBUTES_H_D7THWFVV
#include <list>
#include <string>
struct Player
{
std::string name;
double x;
double y;
double z;
}; /* ----- end of struct Player ----- */
class PlayerAttributes
{
public:
typedef std::list<Player> Players;
PlayerAttributes(const std::string &sourceDirectory);
Players::iterator begin();
Players::iterator end();
private:
Players m_players;
}; /* ----- end of class PlayerAttributes ----- */
#endif /* end of include guard: PLAYERATTRIBUTES_H_D7THWFVV */

View File

@ -10,26 +10,15 @@ This version is both faster and provides more features than the now deprecated P
Requirements
------------
* libgd
* FreeImage
* sqlite3
* LevelDB (optional, set ENABLE_LEVELDB=1 in CMake to enable)
* hiredis library (optional, set ENABLE_REDIS=1 in CMake to enable)
* Postgres libraries (optional, set ENABLE_POSTGRES=1 in CMake to enable)
* leveldb (optional, set ENABLE_LEVELDB=1 in CMake to enable leveldb support)
* hiredis (optional, set ENABLE_REDIS=1 in CMake to enable redis support)
e.g. on Debian:
^^^^^^^^^^^^^^^
sudo apt-get install libgd-dev libsqlite3-dev libleveldb-dev libhiredis-dev libpq-dev
Windows
^^^^^^^
Minetestmapper for Windows can be downloaded here: https://github.com/minetest/minetestmapper/releases
After extracting the archive, minetestmapper can be invoked from cmd.exe:
::
cd C:\Users\yourname\Desktop\example\path
minetestmapper.exe --help
sudo apt-get install libgd-dev libsqlite3-dev libleveldb-dev libhiredis-dev
Compilation
-----------
@ -54,38 +43,32 @@ Parameters
^^^^^^^^^^
bgcolor:
Background color of image, e.g. ``--bgcolor '#ffffff'``
Background color of image, e.g. ``--bgcolor #ffffff``
scalecolor:
Color of scale marks and text, e.g. ``--scalecolor '#000000'``
Color of scale, e.g. ``--scalecolor #000000``
playercolor:
Color of player indicators, e.g. ``--playercolor '#ff0000'``
Color of player indicators, e.g. ``--playercolor #ff0000``
origincolor:
Color of origin indicator, e.g. ``--origincolor '#ff0000'``
Color of origin indicator, e.g. ``--origincolor #ff0000``
drawscale:
Draw scale(s) with tick marks and numbers, ``--drawscale``
Draw tick marks, ``--drawscale``
drawplayers:
Draw player indicators with name, ``--drawplayers``
Draw player indicators, ``--drawplayers``
draworigin:
Draw origin indicator, ``--draworigin``
drawalpha:
Allow nodes to be drawn with transparency (e.g. water), ``--drawalpha``
extent:
Don't output any imagery, just print the extent of the full map, ``--extent``
Allow nodes to be drawn with transparency, ``--drawalpha``
noshading:
Don't draw shading on nodes, ``--noshading``
noemptyimage:
Don't output anything when the image would be empty, ``--noemptyimage``
min-y:
Don't draw nodes below this y value, e.g. ``--min-y -25``
@ -93,16 +76,16 @@ max-y:
Don't draw nodes above this y value, e.g. ``--max-y 75``
backend:
Override auto-detected map backend; supported: *sqlite3*, *leveldb*, *redis*, *postgresql*, e.g. ``--backend leveldb``
Use specific map backend, supported: *sqlite3*, *leveldb*, *redis*, e.g. ``--backend leveldb``
geometry:
Limit area to specific geometry (*x:z+w+h* where x and z specify the lower left corner), e.g. ``--geometry -800:-800+1600+1600``
Limit area to specific geometry (*x:y+w+h* where x and y specify the lower left corner), e.g. ``--geometry -800:-800+1600+1600``
zoom:
Apply zoom to drawn nodes by enlarging them to n*n squares, e.g. ``--zoom 4``
"Zoom" the image by using more than one pixel per node, e.g. ``--zoom 4``
colors:
Override auto-detected path to colors.txt, e.g. ``--colors ../minetest/mycolors.txt``
Forcefully set path to colors.txt file (it's autodetected otherwise), e.g. ``--colors ../minetest/mycolors.txt``
scales:
Draw scales on specified image edges (letters *t b l r* meaning top, bottom, left and right), e.g. ``--scales tbr``

View File

@ -7,16 +7,12 @@
#include <stdexcept>
#include <cstring>
#include <vector>
#include "TileGenerator.h"
#include "config.h"
#include "PlayerAttributes.h"
#include "BlockDecoder.h"
#include "TileGenerator.h"
#include "ZlibDecompressor.h"
#include "util.h"
#include "db-sqlite3.h"
#if USE_POSTGRESQL
#include "db-postgresql.h"
#endif
#if USE_LEVELDB
#include "db-leveldb.h"
#endif
@ -26,16 +22,9 @@
using namespace std;
template<typename T>
static inline T mymax(T a, T b)
static inline uint16_t readU16(const unsigned char *data)
{
return (a > b) ? a : b;
}
template<typename T>
static inline T mymin(T a, T b)
{
return (a > b) ? b : a;
return data[0] << 8 | data[1];
}
// rounds n (away from 0) to a multiple of f while preserving the sign of n
@ -50,9 +39,27 @@ static int round_multiple_nosign(int n, int f)
return sign * (abs_n + f - (abs_n % f));
}
static inline unsigned int colorSafeBounds (int channel)
static int readBlockContent(const unsigned char *mapData, int version, int datapos)
{
return mymin(mymax(channel, 0), 255);
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 int colorSafeBounds(int color)
{
color = (color > 255) ? 255 : color;
color = (color < 0) ? 0 : color;
return color;
}
static Color mixColors(Color a, Color b)
@ -79,7 +86,6 @@ TileGenerator::TileGenerator():
m_drawScale(false),
m_drawAlpha(false),
m_shading(true),
m_dontWriteEmpty(false),
m_backend(""),
m_xBorder(0),
m_yBorder(0),
@ -209,31 +215,6 @@ void TileGenerator::parseColorsFile(const std::string &fileName)
parseColorsStream(in);
}
void TileGenerator::printGeometry(const std::string &input)
{
string input_path = input;
if (input_path[input.length() - 1] != PATH_SEPARATOR) {
input_path += PATH_SEPARATOR;
}
openDb(input_path);
loadBlocks();
std::cout << "Map extent: "
<< m_xMin*16 << ":" << m_zMin*16
<< "+" << (m_xMax - m_xMin+1)*16
<< "+" << (m_zMax - m_zMin+1)*16
<< std::endl;
closeDatabase();
}
void TileGenerator::setDontWriteEmpty(bool f)
{
m_dontWriteEmpty = f;
}
void TileGenerator::generate(const std::string &input, const std::string &output)
{
string input_path = input;
@ -243,13 +224,6 @@ void TileGenerator::generate(const std::string &input, const std::string &output
openDb(input_path);
loadBlocks();
if (m_dontWriteEmpty && ! m_positions.size())
{
closeDatabase();
return;
}
createImage();
renderMap();
closeDatabase();
@ -281,7 +255,7 @@ void TileGenerator::parseColorsStream(std::istream &in)
if(strlen(line) == 0)
continue;
char name[64 + 1];
char name[64];
unsigned int r, g, b, a, t;
a = 255;
t = 0;
@ -303,16 +277,12 @@ void TileGenerator::openDb(const std::string &input)
std::ifstream ifs((input + "/world.mt").c_str());
if(!ifs.good())
throw std::runtime_error("Failed to read world.mt");
backend = read_setting("backend", ifs);
backend = get_setting("backend", ifs);
ifs.close();
}
if(backend == "sqlite3")
m_db = new DBSQLite3(input);
#if USE_POSTGRESQL
else if(backend == "postgresql")
m_db = new DBPostgreSQL(input);
#endif
#if USE_LEVELDB
else if(backend == "leveldb")
m_db = new DBLevelDB(input);
@ -360,38 +330,19 @@ void TileGenerator::loadBlocks()
void TileGenerator::createImage()
{
const int scale_d = 40; // pixels reserved for a scale
if(!m_drawScale)
m_scales = 0;
// If a geometry is explicitly set, set the bounding box to the requested geometry
// instead of cropping to the content. This way we will always output a full tile
// of the correct size.
if (m_geomX > -2048 && m_geomX2 < 2048)
{
m_xMin = m_geomX;
m_xMax = m_geomX2-1;
}
if (m_geomY > -2048 && m_geomY2 < 2048)
{
m_zMin = m_geomY;
m_zMax = m_geomY2-1;
}
m_mapWidth = (m_xMax - m_xMin + 1) * 16;
m_mapHeight = (m_zMax - m_zMin + 1) * 16;
m_xBorder = (m_scales & SCALE_LEFT) ? scale_d : 0;
m_yBorder = (m_scales & SCALE_TOP) ? scale_d : 0;
if(m_drawScale) {
m_xBorder = (m_scales & SCALE_LEFT) ? 40 : 0;
m_yBorder = (m_scales & SCALE_TOP) ? 40 : 0;
}
m_blockPixelAttributes.setWidth(m_mapWidth);
int image_width, image_height;
image_width = (m_mapWidth * m_zoom) + m_xBorder;
image_width += (m_scales & SCALE_RIGHT) ? scale_d : 0;
image_width += m_drawScale && (m_scales & SCALE_RIGHT) ? 40 : 0;
image_height = (m_mapHeight * m_zoom) + m_yBorder;
image_height += (m_scales & SCALE_BOTTOM) ? scale_d : 0;
image_height += m_drawScale && (m_scales & SCALE_BOTTOM) ? 40 : 0;
if(image_width > 4096 || image_height > 4096)
std::cerr << "Warning: The width or height of the image to be created exceeds 4096 pixels!"
@ -403,7 +354,6 @@ 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;
@ -413,8 +363,10 @@ void TileGenerator::renderMap()
if (position->second != zPos)
continue;
m_readPixels.reset();
m_readInfo.reset();
for (int i = 0; i < 16; ++i) {
m_readPixels[i] = 0;
m_readInfo[i] = 0;
}
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
m_color[i][j] = m_bgColor; // This will be drawn by renderMapBlockBottom() for y-rows with only 'air', 'ignore' or unknown nodes if --drawalpha is used
@ -428,72 +380,163 @@ 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();
blk.reset();
blk.decode(it->second);
if (blk.isEmpty())
continue;
renderMapBlock(blk, pos);
uint8_t version = data[0];
//uint8_t flags = data[1];
// Exit out if all pixels for this MapBlock are covered
if (m_readPixels.full())
size_t dataOffset = 0;
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);
bool allRead = true;
for (int i = 0; i < 16; ++i) {
if (m_readPixels[i] != 0xffff)
allRead = false;
}
if (allRead)
break;
}
if (!m_readPixels.full())
bool allRead = true;
for (int i = 0; i < 16; ++i) {
if (m_readPixels[i] != 0xffff)
allRead = false;
}
if (!allRead)
renderMapBlockBottom(blockStack.begin()->first);
}
if (m_shading)
if(m_shading)
renderShading(zPos);
}
}
void TileGenerator::renderMapBlock(const BlockDecoder &blk, const BlockPos &pos)
void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int version)
{
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) {
int imageY = zBegin + 15 - z;
for (int x = 0; x < 16; ++x) {
if (m_readPixels.get(x, z))
if (m_readPixels[z] & (1 << x))
continue;
int imageX = xBegin + x;
for (int y = maxY; y >= minY; --y) {
string name = blk.getNode(x, y, z);
if (name == "")
int position = x + (y << 4) + (z << 8);
int content = readBlockContent(mapData, version, position);
if (content == m_blockAirId || content == m_blockIgnoreId)
continue;
ColorMap::const_iterator it = m_colorMap.find(name);
if (it == m_colorMap.end()) {
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();
if (m_drawAlpha) {
// mix with previous color (unless first visible time)
if (m_color[z][x].a == 0)
m_color[z][x] = c;
else
m_color[z][x] = mixColors(m_color[z][x], c);
if(m_color[z][x].a == 0xff) {
// color is opaque at this depth (no point continuing)
setZoomed(imageX, imageY, m_color[z][x]);
m_readPixels[z] |= (1 << x);
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
} else {
// near thickness value to thickness of current node
m_thickness[z][x] = (m_thickness[z][x] + color->second.t) / 2.0;
continue;
}
} else {
setZoomed(imageX, imageY, c);
m_readPixels[z] |= (1 << x);
}
if(!(m_readInfo[z] & (1 << x))) {
m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y;
m_readInfo[z] |= (1 << x);
}
} else {
m_unknownNodes.insert(name);
continue;
}
const Color c = it->second.to_color();
if (m_drawAlpha) {
if (m_color[z][x].a == 0)
m_color[z][x] = c; // first visible time, no color mixing
else
m_color[z][x] = mixColors(m_color[z][x], c);
if(m_color[z][x].a < 0xff) {
// near thickness value to thickness of current node
m_thickness[z][x] = (m_thickness[z][x] + it->second.t) / 2.0;
continue;
}
// color became opaque, draw it
setZoomed(imageX, imageY, m_color[z][x]);
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
} else {
setZoomed(imageX, imageY, c.noAlpha());
}
m_readPixels.set(x, z);
// do this afterwards so we can record height values
// inside transparent nodes (water) too
if (!m_readInfo.get(x, z)) {
m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y;
m_readInfo.set(x, z);
}
break;
}
}
@ -502,22 +545,21 @@ void TileGenerator::renderMapBlock(const BlockDecoder &blk, const BlockPos &pos)
void TileGenerator::renderMapBlockBottom(const BlockPos &pos)
{
if (!m_drawAlpha)
return; // "missing" pixels can only happen with --drawalpha
int xBegin = (pos.x - m_xMin) * 16;
int zBegin = (m_zMax - pos.z) * 16;
for (int z = 0; z < 16; ++z) {
int imageY = zBegin + 15 - z;
for (int x = 0; x < 16; ++x) {
if (m_readPixels.get(x, z))
if (m_readPixels[z] & (1 << x))
continue;
int imageX = xBegin + x;
// set color since it wasn't done in renderMapBlock()
setZoomed(imageX, imageY, m_color[z][x]);
m_readPixels.set(x, z);
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
if (m_drawAlpha) {
// set color in case it wasn't done in renderMapBlock()
setZoomed(imageX, imageY, m_color[z][x]);
m_readPixels[z] |= (1 << x);
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
}
}
}
}
@ -542,11 +584,11 @@ void TileGenerator::renderShading(int zPos)
int y1 = m_blockPixelAttributes.attribute(z, x - 1).height;
int y2 = m_blockPixelAttributes.attribute(z - 1, x).height;
int d = ((y - y1) + (y - y2)) * 12;
if (m_drawAlpha) { // less visible shadow with increasing "thickness"
double t = m_blockPixelAttributes.attribute(z, x).thickness * 1.2;
d *= 1.0 - mymin(t, 255.0) / 255.0;
}
d = mymin(d, 36);
if (d > 36)
d = 36;
// more thickness -> less visible shadows: t=0 -> 100% visible, t=255 -> 0% visible
if (m_drawAlpha)
d = d * ((0xFF - m_blockPixelAttributes.attribute(z, x).thickness) / 255.0);
Color c = m_image->getPixel(getImageX(x), getImageY(imageY));
c.r = colorSafeBounds(c.r + d);
@ -560,94 +602,71 @@ void TileGenerator::renderShading(int zPos)
void TileGenerator::renderScale()
{
const int scale_d = 40; // see createImage()
if (m_scales & SCALE_TOP) {
m_image->drawText(24, 0, "X", m_scaleColor);
for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4) {
std::ostringstream buf;
stringstream buf;
buf << i * 16;
int xPos = getImageX(i * 16, true);
if (xPos >= 0) {
m_image->drawText(xPos + 2, 0, buf.str(), m_scaleColor);
m_image->drawLine(xPos, 0, xPos, m_yBorder - 1, m_scaleColor);
}
int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder;
m_image->drawText(xPos + 2, 0, buf.str(), m_scaleColor);
m_image->drawLine(xPos, 0, xPos, m_yBorder - 1, m_scaleColor);
}
}
if (m_scales & SCALE_LEFT) {
m_image->drawText(2, 24, "Z", m_scaleColor);
for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4) {
std::ostringstream buf;
stringstream buf;
buf << i * 16;
int yPos = getImageY(i * 16 + 1, true);
if (yPos >= 0) {
m_image->drawText(2, yPos, buf.str(), m_scaleColor);
m_image->drawLine(0, yPos, m_xBorder - 1, yPos, m_scaleColor);
}
int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder;
m_image->drawText(2, yPos, buf.str(), m_scaleColor);
m_image->drawLine(0, yPos, m_xBorder - 1, yPos, m_scaleColor);
}
}
if (m_scales & SCALE_BOTTOM) {
int xPos = m_xBorder + m_mapWidth*m_zoom - 24 - 8,
yPos = m_yBorder + m_mapHeight*m_zoom + scale_d - 12;
m_image->drawText(xPos, yPos, "X", m_scaleColor);
for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4) {
std::ostringstream buf;
stringstream buf;
buf << i * 16;
xPos = getImageX(i * 16, true);
yPos = m_yBorder + m_mapHeight*m_zoom;
if (xPos >= 0) {
m_image->drawText(xPos + 2, yPos, buf.str(), m_scaleColor);
m_image->drawLine(xPos, yPos, xPos, yPos + 39, m_scaleColor);
}
int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder;
int yPos = m_yBorder + m_mapHeight*m_zoom;
m_image->drawText(xPos + 2, yPos, buf.str(), m_scaleColor);
m_image->drawLine(xPos, yPos, xPos, yPos + 39, m_scaleColor);
}
}
if (m_scales & SCALE_RIGHT) {
int xPos = m_xBorder + m_mapWidth*m_zoom + scale_d - 2 - 8,
yPos = m_yBorder + m_mapHeight*m_zoom - 24 - 12;
m_image->drawText(xPos, yPos, "Z", m_scaleColor);
for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4) {
std::ostringstream buf;
stringstream buf;
buf << i * 16;
xPos = m_xBorder + m_mapWidth*m_zoom;
yPos = getImageY(i * 16 + 1, true);
if (yPos >= 0) {
m_image->drawText(xPos + 2, yPos, buf.str(), m_scaleColor);
m_image->drawLine(xPos, yPos, xPos + 39, yPos, m_scaleColor);
}
int xPos = m_xBorder + m_mapWidth*m_zoom;
int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder;
m_image->drawText(xPos + 2, yPos, buf.str(), m_scaleColor);
m_image->drawLine(xPos, yPos, xPos + 39, yPos, m_scaleColor);
}
}
}
void TileGenerator::renderOrigin()
{
if (m_xMin > 0 || m_xMax < 0 ||
m_zMin > 0 || m_zMax < 0)
return;
m_image->drawCircle(getImageX(0, true), getImageY(0, true), 12, m_originColor);
int imageX = (-m_xMin * 16)*m_zoom + m_xBorder;
int imageY = (m_mapHeight - m_zMin * -16)*m_zoom + m_yBorder;
m_image->drawCircle(imageX, imageY, 12, m_originColor);
}
void TileGenerator::renderPlayers(const std::string &inputPath)
{
PlayerAttributes players(inputPath);
for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) {
if (player->x < m_xMin * 16 || player->x > m_xMax * 16 ||
player->z < m_zMin * 16 || player->z > m_zMax * 16)
continue;
if (player->y < m_yMin || player->y > m_yMax)
continue;
int imageX = getImageX(player->x, true),
imageY = getImageY(player->z, true);
int imageX = (player->x / 10 - m_xMin * 16)*m_zoom + m_xBorder;
int imageY = (m_mapHeight - (player->z / 10 - m_zMin * 16))*m_zoom + m_yBorder;
m_image->drawFilledRect(imageX - 1, imageY, 3, 1, m_playerColor);
m_image->drawFilledRect(imageX, imageY - 1, 1, 3, m_playerColor);
m_image->drawText(imageX + 2, imageY, player->name, m_playerColor);
m_image->drawCircle(imageX, imageY, 5, m_playerColor);
m_image->drawText(imageX + 2, imageY + 2, player->name, m_playerColor);
}
}
@ -671,24 +690,21 @@ void TileGenerator::writeImage(const std::string &output)
void TileGenerator::printUnknown()
{
if (m_unknownNodes.size() == 0)
return;
std::cerr << "Unknown nodes:" << std::endl;
for (NameSet::iterator node = m_unknownNodes.begin(); node != m_unknownNodes.end(); ++node)
std::cerr << "\t" << *node << std::endl;
if (m_unknownNodes.size() > 0) {
std::cerr << "Unknown nodes:" << std::endl;
for (NameSet::iterator node = m_unknownNodes.begin(); node != m_unknownNodes.end(); ++node) {
std::cerr << *node << std::endl;
}
}
}
inline int TileGenerator::getImageX(int val, bool absolute) const
inline int TileGenerator::getImageX(int val) const
{
if (absolute)
val = (val - m_xMin * 16);
return (m_zoom*val) + m_xBorder;
}
inline int TileGenerator::getImageY(int val, bool absolute) const
inline int TileGenerator::getImageY(int val) const
{
if (absolute)
val = m_mapHeight - (val - m_zMin * 16); // Z axis is flipped on image
return (m_zoom*val) + m_yBorder;
}

View File

@ -13,9 +13,7 @@
#endif
#include <stdint.h>
#include <string>
#include "PixelAttributes.h"
#include "BlockDecoder.h"
#include "Image.h"
#include "db.h"
#include "types.h"
@ -31,29 +29,11 @@ struct ColorEntry {
ColorEntry(): r(0), g(0), b(0), a(0), t(0) {};
ColorEntry(uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t t): r(r), g(g), b(b), a(a), t(t) {};
inline Color to_color() const { return Color(r, g, b, a); }
uint8_t r, g, b, a, t;
};
struct BitmapThing { // 16x16 bitmap
inline void reset() {
for (int i = 0; i < 16; ++i)
val[i] = 0;
}
inline bool full() const {
for (int i = 0; i < 16; ++i) {
if (val[i] != 0xffff)
return false;
}
return true;
}
inline void set(unsigned int x, unsigned int z) {
val[z] |= (1 << x);
}
inline bool get(unsigned int x, unsigned int z) {
return !!(val[z] & (1 << x));
}
uint16_t val[16];
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
uint8_t t;
};
@ -62,9 +42,11 @@ class TileGenerator
private:
#if __cplusplus >= 201103L
typedef std::unordered_map<std::string, ColorEntry> ColorMap;
typedef std::unordered_map<int, std::string> NameMap;
typedef std::unordered_set<std::string> NameSet;
#else
typedef std::map<std::string, ColorEntry> ColorMap;
typedef std::map<int, std::string> NameMap;
typedef std::set<std::string> NameSet;
#endif
@ -86,10 +68,8 @@ public:
void parseColorsFile(const std::string &fileName);
void setBackend(std::string backend);
void generate(const std::string &input, const std::string &output);
void printGeometry(const std::string &input);
void setZoom(int zoom);
void setScales(uint flags);
void setDontWriteEmpty(bool f);
private:
void parseColorsStream(std::istream &in);
@ -99,7 +79,7 @@ private:
void createImage();
void renderMap();
std::list<int> getZValueList() const;
void renderMapBlock(const BlockDecoder &blk, const BlockPos &pos);
void renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int version);
void renderMapBlockBottom(const BlockPos &pos);
void renderShading(int zPos);
void renderScale();
@ -107,8 +87,8 @@ private:
void renderPlayers(const std::string &inputPath);
void writeImage(const std::string &output);
void printUnknown();
int getImageX(int val, bool absolute=false) const;
int getImageY(int val, bool absolute=false) const;
int getImageX(int val) const;
int getImageY(int val) const;
void setZoomed(int x, int y, Color color);
private:
@ -121,7 +101,6 @@ private:
bool m_drawScale;
bool m_drawAlpha;
bool m_shading;
bool m_dontWriteEmpty;
std::string m_backend;
int m_xBorder, m_yBorder;
@ -141,13 +120,16 @@ private:
int m_mapWidth;
int m_mapHeight;
std::list<std::pair<int, int> > m_positions;
NameMap m_nameMap;
ColorMap m_colorMap;
BitmapThing m_readPixels;
BitmapThing m_readInfo;
uint16_t m_readPixels[16];
uint16_t m_readInfo[16];
NameSet m_unknownNodes;
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

View File

@ -1,14 +1,11 @@
==FILE== mods/dumpnodes/init.lua
local function nd_get_tiles(nd)
return nd.tiles or nd.tile_images
end
local function nd_get_tile(nd, n)
local tile = nd_get_tiles(nd)[n]
if type(tile) == 'table' then
tile = tile.name
if nd.tiles then
return nd.tiles
elseif nd.tile_images then
return nd.tile_images
end
return tile
return nil
end
local function pairs_s(dict)
@ -23,19 +20,19 @@ end
minetest.register_chatcommand("dumpnodes", {
params = "",
description = "",
func = function(player, param)
func = function(plname, param)
local n = 0
local ntbl = {}
for _, nn in pairs_s(minetest.registered_nodes) do
local nd = minetest.registered_nodes[nn]
local prefix, name = nn:match('(.*):(.*)')
if prefix == nil or name == nil then
if prefix == nil or name == nil or prefix == '' or name == '' then
print("ignored(1): " .. nn)
else
if ntbl[prefix] == nil then
ntbl[prefix] = {}
end
ntbl[prefix][name] = true
ntbl[prefix][name] = nd
end
end
local out, err = io.open('nodes.txt', 'wb')
@ -43,17 +40,20 @@ minetest.register_chatcommand("dumpnodes", {
return true, "io.open(): " .. err
end
for _, prefix in pairs_s(ntbl) do
local nodes = ntbl[prefix]
out:write('# ' .. prefix .. '\n')
for _, name in pairs_s(ntbl[prefix]) do
local nn = prefix .. ":" .. name
local nd = minetest.registered_nodes[nn]
if nd.drawtype == 'airlike' or nd_get_tiles(nd) == nil then
print("ignored(2): " .. nn)
else
local tl = nd_get_tile(nd, 1)
tl = (tl .. '^'):match('(.-)^') -- strip modifiers
out:write(nn .. ' ' .. tl .. '\n')
for _, name in pairs_s(nodes) do
local nd = nodes[name]
if nd.drawtype ~= 'airlike' and nd_get_tiles(nd) ~= nil then
local tl = nd_get_tiles(nd)[1]
if type(tl) == 'table' then
tl = tl.name
end
tl = (tl .. '^'):match('(.-)^')
out:write(prefix .. ':' .. name .. ' ' .. tl .. '\n')
n = n + 1
else
print("ignored(2): " .. prefix .. ':' .. name)
end
end
out:write('\n')
@ -65,68 +65,71 @@ minetest.register_chatcommand("dumpnodes", {
==FILE== avgcolor.py
#!/usr/bin/env python
import sys
from math import sqrt
from PIL import Image
def tsum(a, b):
return tuple(sum(e) for e in zip(a, b))
if len(sys.argv) < 2:
print("Prints average color (RGB) of input image")
print("Usage: %s <input>" % sys.argv[0])
exit(1)
inp = Image.open(sys.argv[1]).convert('RGBA')
inp = Image.open(sys.argv[1])
inp = inp.convert('RGBA')
ind = inp.load()
cl = ([], [], [])
cl = (0, 0, 0)
counted = 0
for x in range(inp.size[0]):
for y in range(inp.size[1]):
px = ind[x, y]
if px[3] < 128: continue # alpha
cl[0].append(px[0]**2)
cl[1].append(px[1]**2)
cl[2].append(px[2]**2)
if px[3] < 128:
continue
cl = tsum(cl, px[:3])
counted = counted + 1
if len(cl[0]) == 0:
print("Didn't find average color for %s" % sys.argv[1], file=sys.stderr)
if counted == 0:
sys.stderr.write("didn't find avg. color for %s\n" % sys.argv[1])
print("0 0 0")
else:
cl = tuple(sqrt(sum(x)/len(x)) for x in cl)
print("%d %d %d" % cl)
exit(0)
cl = tuple(int(n / counted) for n in cl)
print("%d %d %d" % cl)
==SCRIPT==
#!/bin/bash -e
AVGCOLOR_PATH=/path/to/avgcolor.py
GAME_PATH=/path/to/minetest_game
MODS_PATH= # path to "mods" folder, only set if you have loaded mods
MTGAME_PATH=/path/to/minetest_game
NODESTXT_PATH=./nodes.txt
COLORSTXT_PATH=./colors.txt
while read -r line; do
set -- junk $line; shift
set -- junk $line
shift
if [[ -z "$1" || $1 == "#" ]]; then
echo "$line"; continue
echo $line
continue
fi
tex=$(find $GAME_PATH -type f -name "$2")
[[ -z "$tex" && -n "$MODS_PATH" ]] && tex=$(find $MODS_PATH -type f -name "$2")
tex=$(find $MTGAME_PATH -type f -name "$2")
if [ -z "$tex" ]; then
echo "skip $1: texture not found" >&2
continue
fi
echo "$1" $(python $AVGCOLOR_PATH "$tex")
echo $1 $(python $AVGCOLOR_PATH "$tex")
echo "ok $1" >&2
done < $NODESTXT_PATH > $COLORSTXT_PATH
# Use nicer colors for water and lava:
sed -re 's/^default:((river_)?water_(flowing|source)) [0-9 ]+$/default:\1 39 66 106 128 224/g' $COLORSTXT_PATH -i
sed -re 's/^default:(lava_(flowing|source)) [0-9 ]+$/default:\1 255 100 0/g' $COLORSTXT_PATH -i
# Add transparency to glass nodes and xpanes:
# Add transparency to glass nodes:
sed -re 's/^default:(.*glass) ([0-9 ]+)$/default:\1 \2 64 16/g' $COLORSTXT_PATH -i
sed -re 's/^doors:(.*glass[^ ]*) ([0-9 ]+)$/doors:\1 \2 64 16/g' $COLORSTXT_PATH -i
sed -re 's/^xpanes:(.*(pane|bar)[^ ]*) ([0-9 ]+)$/xpanes:\1 \3 64 16/g' $COLORSTXT_PATH -i
# Delete some usually hidden nodes:
sed '/^doors:hidden /d' $COLORSTXT_PATH -i
sed '/^fireflies:firefly /d' $COLORSTXT_PATH -i
sed '/^butterflies:butterfly_/d' $COLORSTXT_PATH -i
# Fix xpanes color:
sed -re 's/^xpanes:((pane|bar)(_flat)?) [0-9 ]+$/xpanes:\1 194 194 227 64 16/g' $COLORSTXT_PATH -i
==INSTRUCTIONS==
1) Make sure avgcolors.py works (outputs the usage instructions when run)
1) Make sure avgcolors.py outputs the usage instructions
2) Add the dumpnodes mod to Minetest
3) Create a world and load dumpnodes & all mods you want to generate colors for
4) Execute /dumpnodes ingame
5) Run the script to generate colors.txt (make sure to adjust the PATH variables at the top)
5) Run the script to generate colors.txt (make sure to replace /path/to/... with the actual paths)

View File

@ -3,7 +3,6 @@
#ifndef CMAKE_CONFIG_H
#define CMAKE_CONFIG_H
#define USE_POSTGRESQL @USE_POSTGRESQL@
#define USE_LEVELDB @USE_LEVELDB@
#define USE_REDIS @USE_REDIS@

View File

@ -1,441 +1,277 @@
# beds
beds:bed_bottom 130 3 3
beds:bed_top 185 162 163
beds:fancy_bed_bottom 136 49 28
beds:fancy_bed_top 179 153 148
beds:bed_top 178 116 116
beds:fancy_bed_bottom 135 23 14
beds:fancy_bed_top 172 112 103
# bones
bones:bones 117 117 117
# butterflies
# carts
carts:brakerail 138 121 102
carts:powerrail 160 145 102
carts:rail 146 128 108
bones:bones 86 86 86
# default
default:acacia_bush_leaves 109 133 87
default:acacia_bush_sapling 85 121 61
default:acacia_bush_stem 84 77 70
default:acacia_leaves 126 153 101
default:acacia_sapling 87 120 64
default:acacia_tree 195 119 97
default:acacia_wood 150 61 39
default:apple 161 34 19
default:aspen_leaves 72 105 29
default:aspen_sapling 85 123 45
default:aspen_tree 218 198 168
default:aspen_wood 210 199 170
default:blueberry_bush_leaves 63 99 22
default:blueberry_bush_leaves_with_berries 63 99 22
default:blueberry_bush_sapling 81 112 33
default:bookshelf 131 102 57
default:brick 123 99 95
default:bronzeblock 186 111 15
default:bush_leaves 35 55 29
default:bush_sapling 66 64 40
default:bush_stem 46 34 24
default:cactus 70 119 52
default:cave_ice 168 206 247
default:chest 149 115 69
default:chest_locked 149 115 69
default:chest_locked_open 149 115 69
default:chest_open 149 115 69
default:clay 183 183 183
default:acacia_leaves 108 147 67
default:acacia_sapling 87 116 61
default:acacia_tree 188 109 90
default:acacia_wood 146 60 37
default:apple 145 20 9
default:aspen_leaves 66 89 38
default:aspen_sapling 82 110 43
default:aspen_tree 218 197 166
default:aspen_wood 209 198 169
default:bookshelf 128 99 55
default:brick 117 71 69
default:bronzeblock 185 110 15
default:cactus 52 116 15
default:chest 140 108 65
default:chest_locked 140 108 65
default:clay 182 182 182
default:cloud 255 255 255
default:coalblock 58 58 58
default:cobble 89 86 84
default:copperblock 193 126 65
default:coral_brown 146 113 77
default:coral_cyan 235 230 215
default:coral_green 235 230 215
default:coral_orange 197 68 17
default:coral_pink 235 230 215
default:coral_skeleton 235 230 215
default:desert_cobble 110 67 50
default:coalblock 57 57 57
default:cobble 88 84 82
default:copperblock 192 126 63
default:desert_cobble 146 95 76
default:desert_sand 206 165 98
default:desert_sandstone 195 152 92
default:desert_sandstone_block 193 152 94
default:desert_sandstone_brick 191 151 95
default:desert_stone 130 79 61
default:desert_stone_block 131 80 61
default:desert_stonebrick 131 80 61
default:diamondblock 140 218 223
default:dirt 97 67 43
default:dirt_with_coniferous_litter 109 90 71
default:dirt_with_dry_grass 187 148 78
default:dirt_with_grass 64 111 26
default:dirt_with_grass_footsteps 64 111 26
default:dirt_with_rainforest_litter 76 39 10
default:dirt_with_snow 225 225 238
default:dry_dirt 178 136 90
default:dry_dirt_with_dry_grass 187 148 78
default:desert_stone 129 79 60
default:desert_stone_block 130 79 60
default:desert_stonebrick 129 79 60
default:diamondblock 135 217 223
default:dirt 95 64 39
default:dirt_with_dry_grass 187 148 77
default:dirt_with_grass 66 112 31
default:dirt_with_grass_footsteps 66 112 31
default:dirt_with_snow 223 224 236
default:dry_grass_1 208 172 87
default:dry_grass_2 210 174 87
default:dry_grass_3 210 174 87
default:dry_grass_4 211 175 88
default:dry_grass_5 214 178 92
default:dry_shrub 103 67 18
default:emergent_jungle_sapling 51 40 16
default:fence_acacia_wood 151 62 39
default:dry_grass_5 213 178 92
default:dry_shrub 101 66 17
default:fence_acacia_wood 147 60 38
default:fence_aspen_wood 210 199 170
default:fence_junglewood 57 39 14
default:fence_pine_wood 221 185 131
default:fence_rail_acacia_wood 150 61 39
default:fence_rail_aspen_wood 209 198 170
default:fence_rail_junglewood 56 39 14
default:fence_rail_pine_wood 221 184 130
default:fence_rail_wood 131 102 57
default:fence_wood 132 103 57
default:fern_1 85 118 51
default:fern_2 90 123 53
default:fern_3 91 125 54
default:furnace 101 98 96
default:furnace_active 101 98 96
default:glass 247 247 247 64 16
default:goldblock 231 203 35
default:grass_1 100 140 54
default:grass_2 98 139 55
default:grass_3 94 136 53
default:grass_4 89 133 48
default:grass_5 86 126 48
default:gravel 132 132 132
default:ice 168 206 247
default:junglegrass 67 110 28
default:jungleleaves 22 31 16
default:junglesapling 51 39 15
default:jungletree 121 97 62
default:junglewood 56 39 14
default:ladder_steel 132 132 132
default:ladder_wood 125 93 43
default:large_cactus_seedling 67 107 52
default:fence_junglewood 54 37 11
default:fence_pine_wood 221 184 129
default:fence_wood 129 100 55
default:furnace 100 96 94
default:furnace_active 100 96 94
default:glass 194 194 227 64 16
default:goldblock 230 201 29
default:grass_1 97 138 53
default:grass_2 95 136 54
default:grass_3 91 133 52
default:grass_4 86 130 45
default:grass_5 83 124 47
default:gravel 131 131 131
default:ice 167 206 247
default:junglegrass 63 105 25
default:jungleleaves 20 28 15
default:junglesapling 48 38 14
default:jungletree 105 76 41
default:junglewood 54 37 11
default:ladder_steel 126 126 126
default:ladder_wood 123 90 34
default:lava_flowing 255 100 0
default:lava_source 255 100 0
default:leaves 36 55 29
default:marram_grass_1 113 139 96
default:marram_grass_2 102 131 90
default:marram_grass_3 99 130 88
default:mese 222 222 0
default:mese_post_light 134 105 59
default:meselamp 213 215 143
default:mossycobble 88 91 73
default:obsidian 21 24 29
default:obsidian_block 23 25 30
default:obsidian_glass 20 23 27 64 16
default:obsidianbrick 23 25 29
default:papyrus 97 134 38
default:permafrost 71 66 61
default:permafrost_with_moss 108 150 51
default:permafrost_with_stones 71 66 61
default:pine_bush_needles 16 50 19
default:pine_bush_sapling 58 51 40
default:pine_bush_stem 73 62 53
default:pine_needles 16 50 19
default:pine_sapling 41 48 26
default:pine_tree 191 165 132
default:pine_wood 221 185 130
default:leaves 34 52 29
default:mese 220 220 0
default:meselamp 211 213 139
default:mossycobble 86 90 68
default:obsidian 19 21 24
default:obsidian_block 20 22 25
default:obsidian_glass 19 21 23 64 16
default:obsidianbrick 20 22 24
default:papyrus 94 132 33
default:pine_needles 13 36 21
default:pine_sapling 27 48 25
default:pine_tree 182 155 124
default:pine_wood 221 184 128
default:rail 143 123 90
default:river_water_flowing 39 66 106 128 224
default:river_water_source 39 66 106 128 224
default:sand 214 207 158
default:sand_with_kelp 214 207 158
default:sandstone 198 193 143
default:sandstone_block 195 191 142
default:sandstonebrick 194 190 141
default:sapling 67 63 41
default:sign_wall_steel 147 147 147
default:sign_wall_wood 148 103 66
default:sandstone 197 193 143
default:sandstone_block 195 190 141
default:sandstonebrick 193 189 140
default:sapling 65 59 40
default:sign_wall_steel 144 144 144
default:sign_wall_wood 145 101 64
default:silver_sand 193 191 179
default:silver_sandstone 195 192 181
default:silver_sandstone_block 192 190 180
default:silver_sandstone_brick 191 189 179
default:snow 225 225 238
default:snowblock 225 225 238
default:steelblock 195 195 195
default:snow 223 224 236
default:snowblock 223 224 236
default:steelblock 194 194 194
default:stone 97 94 93
default:stone_block 100 97 96
default:stone_block 99 96 95
default:stone_with_coal 97 94 93
default:stone_with_copper 97 94 93
default:stone_with_diamond 97 94 93
default:stone_with_gold 97 94 93
default:stone_with_iron 97 94 93
default:stone_with_mese 97 94 93
default:stone_with_tin 97 94 93
default:stonebrick 102 99 98
default:tinblock 150 150 150
default:torch 141 123 93
default:torch_ceiling 141 123 93
default:torch_wall 141 123 93
default:tree 179 145 99
default:stonebrick 99 96 95
default:torch 120 98 67
default:tree 164 131 88
default:water_flowing 39 66 106 128 224
default:water_source 39 66 106 128 224
default:wood 131 102 57
default:wood 128 99 55
# doors
doors:door_glass_a 245 245 245 64 16
doors:door_glass_b 245 245 245 64 16
doors:door_obsidian_glass_a 48 49 50 64 16
doors:door_obsidian_glass_b 48 49 50 64 16
doors:door_steel_a 203 203 203
doors:door_steel_b 203 203 203
doors:door_wood_a 89 68 37
doors:door_wood_b 89 68 37
doors:gate_acacia_wood_closed 150 61 39
doors:gate_acacia_wood_open 150 61 39
doors:gate_aspen_wood_closed 210 199 170
doors:gate_aspen_wood_open 210 199 170
doors:gate_junglewood_closed 56 39 14
doors:gate_junglewood_open 56 39 14
doors:gate_pine_wood_closed 221 185 130
doors:gate_pine_wood_open 221 185 130
doors:gate_wood_closed 131 102 57
doors:gate_wood_open 131 102 57
doors:trapdoor 130 100 51
doors:trapdoor_open 68 53 30
doors:trapdoor_steel 200 200 200
doors:trapdoor_steel_open 97 97 97
doors:door_glass_a 184 184 216 64 16
doors:door_glass_b 184 184 216 64 16
doors:door_obsidian_glass_a 27 28 29 64 16
doors:door_obsidian_glass_b 27 28 29 64 16
doors:door_steel_a 201 201 201
doors:door_steel_b 201 201 201
doors:door_wood_a 87 67 35
doors:door_wood_b 87 67 35
doors:gate_acacia_wood_closed 146 60 37
doors:gate_acacia_wood_open 146 60 37
doors:gate_aspen_wood_closed 209 198 169
doors:gate_aspen_wood_open 209 198 169
doors:gate_junglewood_closed 54 37 11
doors:gate_junglewood_open 54 37 11
doors:gate_pine_wood_closed 221 184 128
doors:gate_pine_wood_open 221 184 128
doors:gate_wood_closed 128 99 55
doors:gate_wood_open 128 99 55
doors:hidden 0 0 0
doors:trapdoor 128 99 50
doors:trapdoor_open 225 217 206
doors:trapdoor_steel 199 199 199
doors:trapdoor_steel_open 206 206 206
# farming
farming:cotton_1 89 117 39
farming:cotton_2 89 116 38
farming:cotton_3 99 121 41
farming:cotton_4 108 114 47
farming:cotton_5 116 105 53
farming:cotton_6 121 95 59
farming:cotton_7 94 70 37
farming:cotton_8 122 108 93
farming:desert_sand_soil 161 132 72
farming:desert_sand_soil_wet 120 99 53
farming:dry_soil 178 136 90
farming:dry_soil_wet 178 136 90
farming:seed_cotton 92 87 60
farming:seed_wheat 177 161 96
farming:soil 97 67 43
farming:soil_wet 97 67 43
farming:straw 212 184 68
farming:wheat_1 110 175 36
farming:wheat_2 136 177 53
farming:wheat_3 163 182 84
farming:wheat_4 170 188 95
farming:wheat_5 171 179 97
farming:wheat_6 173 177 87
farming:wheat_7 193 181 83
farming:wheat_8 187 162 40
farming:cotton_1 88 116 39
farming:cotton_2 87 116 38
farming:cotton_3 97 120 41
farming:cotton_4 106 113 47
farming:cotton_5 114 104 53
farming:cotton_6 119 94 59
farming:cotton_7 92 69 37
farming:cotton_8 110 91 61
farming:desert_sand_soil 159 131 70
farming:desert_sand_soil_wet 119 98 52
farming:seed_cotton 90 85 57
farming:seed_wheat 175 159 93
farming:soil 95 64 39
farming:soil_wet 95 64 39
farming:straw 211 182 67
farming:wheat_1 107 174 32
farming:wheat_2 133 175 50
farming:wheat_3 162 182 82
farming:wheat_4 169 187 93
farming:wheat_5 169 178 94
farming:wheat_6 172 176 85
farming:wheat_7 192 181 81
farming:wheat_8 186 161 35
# fire
fire:basic_flame 223 136 44
fire:permanent_flame 223 136 44
# fireflies
fireflies:firefly_bottle 191 194 202
fire:basic_flame 218 120 36
fire:permanent_flame 218 120 36
# flowers
flowers:chrysanthemum_green 118 152 44
flowers:dandelion_white 199 191 176
flowers:dandelion_yellow 212 167 31
flowers:geranium 77 91 168
flowers:mushroom_brown 109 84 78
flowers:mushroom_red 195 102 102
flowers:rose 130 68 33
flowers:tulip 156 101 44
flowers:tulip_black 78 120 72
flowers:viola 115 69 184
flowers:waterlily 107 160 68
flowers:waterlily_waving 107 160 68
flowers:dandelion_white 178 176 140
flowers:dandelion_yellow 178 148 24
flowers:geranium 72 87 155
flowers:mushroom_brown 106 79 72
flowers:mushroom_red 192 85 85
flowers:rose 118 48 24
flowers:tulip 130 99 36
flowers:viola 106 60 159
flowers:waterlily 102 158 61
# nyancat
nyancat:nyancat 198 111 167
nyancat:nyancat_rainbow 123 100 94
# stairs
stairs:slab_acacia_wood 150 61 39
stairs:slab_aspen_wood 210 199 170
stairs:slab_brick 123 99 95
stairs:slab_bronzeblock 186 111 15
stairs:slab_cobble 89 86 84
stairs:slab_copperblock 193 126 65
stairs:slab_desert_cobble 110 67 50
stairs:slab_desert_sandstone 195 152 92
stairs:slab_desert_sandstone_block 193 152 94
stairs:slab_desert_sandstone_brick 191 151 95
stairs:slab_desert_stone 130 79 61
stairs:slab_desert_stone_block 131 80 61
stairs:slab_desert_stonebrick 131 80 61
stairs:slab_glass 247 247 247
stairs:slab_goldblock 231 203 35
stairs:slab_ice 168 206 247
stairs:slab_junglewood 56 39 14
stairs:slab_mossycobble 88 91 73
stairs:slab_obsidian 21 24 29
stairs:slab_obsidian_block 23 25 30
stairs:slab_obsidian_glass 20 23 27
stairs:slab_obsidianbrick 23 25 29
stairs:slab_pine_wood 221 185 130
stairs:slab_sandstone 198 193 143
stairs:slab_sandstone_block 195 191 142
stairs:slab_sandstonebrick 194 190 141
stairs:slab_silver_sandstone 195 192 181
stairs:slab_silver_sandstone_block 192 190 180
stairs:slab_silver_sandstone_brick 191 189 179
stairs:slab_snowblock 225 225 238
stairs:slab_steelblock 195 195 195
stairs:slab_acacia_wood 146 60 37
stairs:slab_aspen_wood 209 198 169
stairs:slab_brick 117 71 69
stairs:slab_bronzeblock 185 110 15
stairs:slab_cobble 88 84 82
stairs:slab_copperblock 192 126 63
stairs:slab_desert_cobble 146 95 76
stairs:slab_desert_stone 129 79 60
stairs:slab_desert_stone_block 130 79 60
stairs:slab_desert_stonebrick 129 79 60
stairs:slab_goldblock 230 201 29
stairs:slab_junglewood 54 37 11
stairs:slab_mossycobble 86 90 68
stairs:slab_obsidian 19 21 24
stairs:slab_obsidian_block 20 22 25
stairs:slab_obsidianbrick 20 22 24
stairs:slab_pine_wood 221 184 128
stairs:slab_sandstone 197 193 143
stairs:slab_sandstone_block 195 190 141
stairs:slab_sandstonebrick 193 189 140
stairs:slab_steelblock 194 194 194
stairs:slab_stone 97 94 93
stairs:slab_stone_block 100 97 96
stairs:slab_stonebrick 102 99 98
stairs:slab_straw 212 184 68
stairs:slab_tinblock 150 150 150
stairs:slab_wood 131 102 57
stairs:stair_acacia_wood 150 61 39
stairs:stair_aspen_wood 210 199 170
stairs:stair_brick 123 99 95
stairs:stair_bronzeblock 186 111 15
stairs:stair_cobble 89 86 84
stairs:stair_copperblock 193 126 65
stairs:stair_desert_cobble 110 67 50
stairs:stair_desert_sandstone 195 152 92
stairs:stair_desert_sandstone_block 193 152 94
stairs:stair_desert_sandstone_brick 191 151 95
stairs:stair_desert_stone 130 79 61
stairs:stair_desert_stone_block 131 80 61
stairs:stair_desert_stonebrick 131 80 61
stairs:stair_glass 249 249 249
stairs:stair_goldblock 231 203 35
stairs:stair_ice 168 206 247
stairs:stair_inner_acacia_wood 150 61 39
stairs:stair_inner_aspen_wood 210 199 170
stairs:stair_inner_brick 123 99 95
stairs:stair_inner_bronzeblock 186 111 15
stairs:stair_inner_cobble 89 86 84
stairs:stair_inner_copperblock 193 126 65
stairs:stair_inner_desert_cobble 110 67 50
stairs:stair_inner_desert_sandstone 195 152 92
stairs:stair_inner_desert_sandstone_block 193 152 94
stairs:stair_inner_desert_sandstone_brick 191 151 95
stairs:stair_inner_desert_stone 130 79 61
stairs:stair_inner_desert_stone_block 131 80 61
stairs:stair_inner_desert_stonebrick 131 80 61
stairs:stair_inner_glass 250 250 250
stairs:stair_inner_goldblock 231 203 35
stairs:stair_inner_ice 168 206 247
stairs:stair_inner_junglewood 56 39 14
stairs:stair_inner_mossycobble 88 91 73
stairs:stair_inner_obsidian 21 24 29
stairs:stair_inner_obsidian_block 23 25 30
stairs:stair_inner_obsidian_glass 20 22 27
stairs:stair_inner_obsidianbrick 23 25 29
stairs:stair_inner_pine_wood 221 185 130
stairs:stair_inner_sandstone 198 193 143
stairs:stair_inner_sandstone_block 195 191 142
stairs:stair_inner_sandstonebrick 194 190 141
stairs:stair_inner_silver_sandstone 195 192 181
stairs:stair_inner_silver_sandstone_block 192 190 180
stairs:stair_inner_silver_sandstone_brick 191 189 179
stairs:stair_inner_snowblock 225 225 238
stairs:stair_inner_steelblock 195 195 195
stairs:stair_inner_stone 97 94 93
stairs:stair_inner_stone_block 100 97 96
stairs:stair_inner_stonebrick 102 99 98
stairs:stair_inner_straw 212 184 68
stairs:stair_inner_tinblock 150 150 150
stairs:stair_inner_wood 131 102 57
stairs:stair_junglewood 56 39 14
stairs:stair_mossycobble 88 91 73
stairs:stair_obsidian 21 24 29
stairs:stair_obsidian_block 23 25 30
stairs:stair_obsidian_glass 20 22 27
stairs:stair_obsidianbrick 23 25 29
stairs:stair_outer_acacia_wood 150 61 39
stairs:stair_outer_aspen_wood 210 199 170
stairs:stair_outer_brick 123 99 95
stairs:stair_outer_bronzeblock 186 111 15
stairs:stair_outer_cobble 89 86 84
stairs:stair_outer_copperblock 193 126 65
stairs:stair_outer_desert_cobble 110 67 50
stairs:stair_outer_desert_sandstone 195 152 92
stairs:stair_outer_desert_sandstone_block 193 152 94
stairs:stair_outer_desert_sandstone_brick 191 151 95
stairs:stair_outer_desert_stone 130 79 61
stairs:stair_outer_desert_stone_block 131 80 61
stairs:stair_outer_desert_stonebrick 131 80 61
stairs:stair_outer_glass 250 250 250
stairs:stair_outer_goldblock 231 203 35
stairs:stair_outer_ice 168 206 247
stairs:stair_outer_junglewood 56 39 14
stairs:stair_outer_mossycobble 88 91 73
stairs:stair_outer_obsidian 21 24 29
stairs:stair_outer_obsidian_block 23 25 30
stairs:stair_outer_obsidian_glass 20 22 27
stairs:stair_outer_obsidianbrick 23 25 29
stairs:stair_outer_pine_wood 221 185 130
stairs:stair_outer_sandstone 198 193 143
stairs:stair_outer_sandstone_block 195 191 142
stairs:stair_outer_sandstonebrick 194 190 141
stairs:stair_outer_silver_sandstone 195 192 181
stairs:stair_outer_silver_sandstone_block 192 190 180
stairs:stair_outer_silver_sandstone_brick 191 189 179
stairs:stair_outer_snowblock 225 225 238
stairs:stair_outer_steelblock 195 195 195
stairs:stair_outer_stone 97 94 93
stairs:stair_outer_stone_block 100 97 96
stairs:stair_outer_stonebrick 102 99 98
stairs:stair_outer_straw 212 184 68
stairs:stair_outer_tinblock 150 150 150
stairs:stair_outer_wood 131 102 57
stairs:stair_pine_wood 221 185 130
stairs:stair_sandstone 198 193 143
stairs:stair_sandstone_block 195 191 142
stairs:stair_sandstonebrick 194 190 141
stairs:stair_silver_sandstone 195 192 181
stairs:stair_silver_sandstone_block 192 190 180
stairs:stair_silver_sandstone_brick 191 189 179
stairs:stair_snowblock 225 225 238
stairs:stair_steelblock 195 195 195
stairs:slab_stone_block 99 96 95
stairs:slab_stonebrick 99 96 95
stairs:slab_straw 211 182 67
stairs:slab_wood 128 99 55
stairs:stair_acacia_wood 146 60 37
stairs:stair_aspen_wood 209 198 169
stairs:stair_brick 117 71 69
stairs:stair_bronzeblock 185 110 15
stairs:stair_cobble 88 84 82
stairs:stair_copperblock 192 126 63
stairs:stair_desert_cobble 146 95 76
stairs:stair_desert_stone 129 79 60
stairs:stair_desert_stone_block 130 79 60
stairs:stair_desert_stonebrick 129 79 60
stairs:stair_goldblock 230 201 29
stairs:stair_junglewood 54 37 11
stairs:stair_mossycobble 86 90 68
stairs:stair_obsidian 19 21 24
stairs:stair_obsidian_block 20 22 25
stairs:stair_obsidianbrick 20 22 24
stairs:stair_pine_wood 221 184 128
stairs:stair_sandstone 197 193 143
stairs:stair_sandstone_block 195 190 141
stairs:stair_sandstonebrick 193 189 140
stairs:stair_steelblock 194 194 194
stairs:stair_stone 97 94 93
stairs:stair_stone_block 100 97 96
stairs:stair_stonebrick 102 99 98
stairs:stair_straw 212 184 68
stairs:stair_tinblock 150 150 150
stairs:stair_wood 131 102 57
stairs:stair_stone_block 99 96 95
stairs:stair_stonebrick 99 96 95
stairs:stair_straw 211 182 67
stairs:stair_wood 128 99 55
# tnt
tnt:gunpowder 12 12 12
tnt:gunpowder_burning 156 143 7
tnt:tnt 196 0 0
tnt:tnt_burning 201 41 0
tnt:gunpowder 6 6 6
tnt:gunpowder_burning 112 103 2
tnt:tnt 181 0 0
tnt:tnt_burning 190 8 0
# vessels
vessels:drinking_glass 207 214 228
vessels:glass_bottle 189 192 204
vessels:shelf 131 102 57
vessels:steel_bottle 194 193 193
vessels:drinking_glass 206 214 228
vessels:glass_bottle 188 190 201
vessels:shelf 128 99 55
vessels:steel_bottle 193 192 191
# walls
walls:cobble 89 86 84
walls:desertcobble 110 67 50
walls:mossycobble 88 91 73
walls:cobble 88 84 82
walls:desertcobble 146 95 76
walls:mossycobble 86 90 68
# wool
wool:black 30 30 30
wool:blue 0 73 146
wool:brown 88 44 0
wool:cyan 0 132 140
wool:dark_green 33 103 0
wool:dark_grey 60 60 60
wool:green 93 218 28
wool:grey 133 133 133
wool:magenta 201 3 112
wool:orange 214 83 22
wool:pink 255 133 133
wool:red 170 18 18
wool:violet 93 5 169
wool:black 29 29 29
wool:blue 0 72 145
wool:brown 86 42 0
wool:cyan 0 130 139
wool:dark_green 32 102 0
wool:dark_grey 59 59 59
wool:green 92 216 28
wool:grey 131 131 131
wool:magenta 200 3 109
wool:orange 213 81 21
wool:pink 255 131 131
wool:red 168 17 17
wool:violet 92 2 169
wool:white 220 220 220
wool:yellow 254 226 16
wool:yellow 254 225 15
# xpanes
xpanes:bar 114 114 114 64 16
xpanes:bar_flat 114 114 114 64 16
xpanes:door_steel_bar_a 133 133 133 64 16
xpanes:door_steel_bar_b 133 133 133 64 16
xpanes:obsidian_pane 16 17 18 64 16
xpanes:obsidian_pane_flat 16 17 18 64 16
xpanes:pane 249 249 249 64 16
xpanes:pane_flat 249 249 249 64 16
xpanes:trapdoor_steel_bar 127 127 127 64 16
xpanes:trapdoor_steel_bar_open 77 77 77 64 16
xpanes:bar 194 194 227 64 16
xpanes:bar_flat 194 194 227 64 16
xpanes:pane 194 194 227 64 16
xpanes:pane_flat 194 194 227 64 16

View File

@ -9,7 +9,6 @@
#ifdef USE_CMAKE_CONFIG_H
#include "cmake_config.h"
#else
#define USE_POSTGRESQL 0
#define USE_LEVELDB 0
#define USE_REDIS 0

View File

@ -1,168 +0,0 @@
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <arpa/inet.h>
#include "db-postgresql.h"
#include "util.h"
#include "types.h"
#define ARRLEN(x) (sizeof(x) / sizeof((x)[0]))
DBPostgreSQL::DBPostgreSQL(const std::string &mapdir)
{
std::ifstream ifs((mapdir + "/world.mt").c_str());
if(!ifs.good())
throw std::runtime_error("Failed to read world.mt");
std::string connect_string = read_setting("pgsql_connection", ifs);
ifs.close();
db = PQconnectdb(connect_string.c_str());
if (PQstatus(db) != CONNECTION_OK) {
throw std::runtime_error(std::string(
"PostgreSQL database error: ") +
PQerrorMessage(db)
);
}
prepareStatement(
"get_block_pos",
"SELECT posX, posY, posZ FROM blocks"
);
prepareStatement(
"get_blocks_z",
"SELECT posX, posY, data FROM blocks WHERE posZ = $1::int4"
);
checkResults(PQexec(db, "START TRANSACTION;"));
checkResults(PQexec(db, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;"));
}
DBPostgreSQL::~DBPostgreSQL()
{
try {
checkResults(PQexec(db, "COMMIT;"));
} catch (std::exception& caught) {
std::cerr << "could not finalize: " << caught.what() << std::endl;
}
PQfinish(db);
}
std::vector<BlockPos> DBPostgreSQL::getBlockPos()
{
std::vector<BlockPos> positions;
PGresult *results = execPrepared(
"get_block_pos", 0,
NULL, NULL, NULL, false, false
);
int numrows = PQntuples(results);
for (int row = 0; row < numrows; ++row)
positions.push_back(pg_to_blockpos(results, row, 0));
PQclear(results);
return positions;
}
void DBPostgreSQL::getBlocksOnZ(std::map<int16_t, BlockList> &blocks, int16_t zPos)
{
int32_t const z = htonl(zPos);
const void *args[] = { &z };
const int argLen[] = { sizeof(z) };
const int argFmt[] = { 1 };
PGresult *results = execPrepared(
"get_blocks_z", ARRLEN(args), args,
argLen, argFmt, false
);
int numrows = PQntuples(results);
for (int row = 0; row < numrows; ++row) {
BlockPos position;
position.x = pg_binary_to_int(results, row, 0);
position.y = pg_binary_to_int(results, row, 1);
position.z = zPos;
Block const b(
position,
ustring(
reinterpret_cast<unsigned char*>(
PQgetvalue(results, row, 2)
),
PQgetlength(results, row, 2)
)
);
blocks[position.x].push_back(b);
}
PQclear(results);
}
PGresult *DBPostgreSQL::checkResults(PGresult *res, bool clear)
{
ExecStatusType statusType = PQresultStatus(res);
switch (statusType) {
case PGRES_COMMAND_OK:
case PGRES_TUPLES_OK:
break;
case PGRES_FATAL_ERROR:
throw std::runtime_error(
std::string("PostgreSQL database error: ") +
PQresultErrorMessage(res)
);
default:
throw std::runtime_error(
"Unhandled PostgreSQL result code"
);
}
if (clear)
PQclear(res);
return res;
}
void DBPostgreSQL::prepareStatement(const std::string &name, const std::string &sql)
{
checkResults(PQprepare(db, name.c_str(), sql.c_str(), 0, NULL));
}
PGresult *DBPostgreSQL::execPrepared(
const char *stmtName, const int paramsNumber,
const void **params,
const int *paramsLengths, const int *paramsFormats,
bool clear, bool nobinary
)
{
return checkResults(PQexecPrepared(db, stmtName, paramsNumber,
(const char* const*) params, paramsLengths, paramsFormats,
nobinary ? 1 : 0), clear
);
}
int DBPostgreSQL::pg_to_int(PGresult *res, int row, int col)
{
return atoi(PQgetvalue(res, row, col));
}
int DBPostgreSQL::pg_binary_to_int(PGresult *res, int row, int col)
{
int32_t* raw = reinterpret_cast<int32_t*>(PQgetvalue(res, row, col));
return ntohl(*raw);
}
BlockPos DBPostgreSQL::pg_to_blockpos(PGresult *res, int row, int col)
{
BlockPos result;
result.x = pg_to_int(res, row, col);
result.y = pg_to_int(res, row, col + 1);
result.z = pg_to_int(res, row, col + 2);
return result;
}

View File

@ -28,24 +28,35 @@ static inline std::string i64tos(int64_t i)
return os.str();
}
std::string get_setting_default(std::string name, std::istream &is, const std::string def)
{
try {
return get_setting(name, is);
} catch(std::runtime_error e) {
return def;
}
}
DBRedis::DBRedis(const std::string &mapdir)
{
std::ifstream ifs((mapdir + "/world.mt").c_str());
if(!ifs.good())
throw std::runtime_error("Failed to read world.mt");
std::string tmp;
tmp = read_setting("redis_address", ifs);
ifs.seekg(0);
hash = read_setting("redis_hash", ifs);
ifs.seekg(0);
try {
tmp = get_setting("redis_address", ifs);
ifs.seekg(0);
hash = get_setting("redis_hash", ifs);
ifs.seekg(0);
} catch(std::runtime_error e) {
throw std::runtime_error("Set redis_address and redis_hash in world.mt to use the redis backend");
}
const char *addr = tmp.c_str();
int port = stoi64(read_setting_default("redis_port", ifs, "6379"));
ctx = tmp.find('/') != std::string::npos ? redisConnectUnix(addr) : redisConnect(addr, port);
if(!ctx) {
int port = stoi64(get_setting_default("redis_port", ifs, "6379"));
ctx = redisConnect(addr, port);
if(!ctx)
throw std::runtime_error("Cannot allocate redis context");
} else if(ctx->err) {
else if(ctx->err) {
std::string err = std::string("Connection error: ") + ctx->errstr;
redisFree(ctx);
throw std::runtime_error(err);

View File

@ -20,18 +20,24 @@ public:
BlockPos(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {}
bool operator < (const BlockPos &p) const
{
if (z > p.z)
if (z > p.z) {
return true;
if (z < p.z)
}
if (z < p.z) {
return false;
if (y > p.y)
}
if (y > p.y) {
return true;
if (y < p.y)
}
if (y < p.y) {
return false;
if (x > p.x)
}
if (x > p.x) {
return true;
if (x < p.x)
}
if (x < p.x) {
return false;
}
return false;
}
};

View File

@ -1,35 +0,0 @@
#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

View File

@ -1,30 +0,0 @@
#ifndef PLAYERATTRIBUTES_H_D7THWFVV
#define PLAYERATTRIBUTES_H_D7THWFVV
#include <list>
#include <string>
struct Player
{
std::string name;
double x, y, z;
};
class PlayerAttributes
{
public:
typedef std::list<Player> Players;
PlayerAttributes(const std::string &worldDir);
Players::iterator begin();
Players::iterator end();
private:
void readFiles(const std::string &playersPath);
void readSqlite(const std::string &db_name);
Players m_players;
};
#endif /* end of include guard: PLAYERATTRIBUTES_H_D7THWFVV */

View File

@ -1,29 +0,0 @@
#ifndef _DB_POSTGRESQL_H
#define _DB_POSTGRESQL_H
#include "db.h"
#include <libpq-fe.h>
class DBPostgreSQL : public DB {
public:
DBPostgreSQL(const std::string &mapdir);
virtual std::vector<BlockPos> getBlockPos();
virtual void getBlocksOnZ(std::map<int16_t, BlockList> &blocks, int16_t zPos);
virtual ~DBPostgreSQL();
protected:
PGresult *checkResults(PGresult *res, bool clear = true);
void prepareStatement(const std::string &name, const std::string &sql);
PGresult *execPrepared(
const char *stmtName, const int paramsNumber,
const void **params,
const int *paramsLengths = NULL, const int *paramsFormats = NULL,
bool clear = true, bool nobinary = true
);
int pg_to_int(PGresult *res, int row, int col);
int pg_binary_to_int(PGresult *res, int row, int col);
BlockPos pg_to_blockpos(PGresult *res, int row, int col);
private:
PGconn *db;
};
#endif // _DB_POSTGRESQL_H

View File

@ -1,18 +0,0 @@
#ifndef UTIL_H
#define UTIL_H
#include <string>
#include <fstream>
std::string read_setting(const std::string &name, std::istream &is);
inline std::string read_setting_default(const std::string &name, std::istream &is, const std::string &def)
{
try {
return read_setting(name, is);
} catch(std::runtime_error &e) {
return def;
}
}
#endif // UTIL_H

View File

@ -24,12 +24,10 @@ void usage()
" --draworigin\n"
" --drawalpha\n"
" --noshading\n"
" --noemptyimage\n"
" --min-y <y>\n"
" --max-y <y>\n"
" --backend <backend>\n"
" --geometry x:y+w+h\n"
" --extent\n"
" --zoom <zoomlevel>\n"
" --colors <colors.txt>\n"
" --scales [t][b][l][r]\n"
@ -82,13 +80,11 @@ int main(int argc, char *argv[])
{"noshading", no_argument, 0, 'H'},
{"backend", required_argument, 0, 'd'},
{"geometry", required_argument, 0, 'g'},
{"extent", no_argument, 0, 'E'},
{"min-y", required_argument, 0, 'a'},
{"max-y", required_argument, 0, 'c'},
{"zoom", required_argument, 0, 'z'},
{"colors", required_argument, 0, 'C'},
{"scales", required_argument, 0, 'f'},
{"noemptyimage", no_argument, 0, 'n'},
{0, 0, 0, 0}
};
@ -97,13 +93,17 @@ int main(int argc, char *argv[])
std::string colors = "";
TileGenerator generator;
bool onlyPrintExtent = false;
int option_index = 0;
int c = 0;
while (1) {
int option_index;
int c = getopt_long(argc, argv, "hi:o:", long_options, &option_index);
if (c == -1)
break; // done
c = getopt_long(argc, argv, "hi:o:", long_options, &option_index);
if (c == -1) {
if (input.empty() || output.empty()) {
usage();
return 0;
}
break;
}
switch (c) {
case 'h':
usage();
@ -139,9 +139,6 @@ int main(int argc, char *argv[])
case 'e':
generator.setDrawAlpha(true);
break;
case 'E':
onlyPrintExtent = true;
break;
case 'H':
generator.setShading(false);
break;
@ -149,21 +146,24 @@ int main(int argc, char *argv[])
generator.setBackend(optarg);
break;
case 'a': {
std::istringstream iss(optarg);
std::istringstream iss;
iss.str(optarg);
int miny;
iss >> miny;
generator.setMinY(miny);
}
break;
case 'c': {
std::istringstream iss(optarg);
std::istringstream iss;
iss.str(optarg);
int maxy;
iss >> maxy;
generator.setMaxY(maxy);
}
break;
case 'g': {
std::istringstream geometry(optarg);
std::istringstream geometry;
geometry.str(optarg);
int x, y, w, h;
char c;
geometry >> x >> c >> y >> w >> h;
@ -188,7 +188,8 @@ int main(int argc, char *argv[])
}
break;
case 'z': {
std::istringstream iss(optarg);
std::istringstream iss;
iss.str(optarg);
int zoom;
iss >> zoom;
generator.setZoom(zoom);
@ -197,32 +198,16 @@ int main(int argc, char *argv[])
case 'C':
colors = optarg;
break;
case 'n':
generator.setDontWriteEmpty(true);
break;
default:
exit(1);
}
}
if (input.empty() || (!onlyPrintExtent && output.empty())) {
usage();
return 0;
}
if(colors == "")
colors = search_colors(input);
try {
if (onlyPrintExtent) {
generator.printGeometry(input);
return 0;
}
if(colors == "")
colors = search_colors(input);
generator.parseColorsFile(colors);
generator.generate(input, output);
} catch(std::runtime_error &e) {
} catch(std::runtime_error e) {
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}

View File

@ -1,99 +0,0 @@
.TH MINETESTMAPPER 6
.SH NAME
minetestmapper \- generate an overview image of a Minetest map
.SH SYNOPSIS
.B minetestmapper
\fB\-i\fR \fIworld_path\fR
\fB\-o\fR \fIoutput_image\fR
.PP
See additional optional parameters below.
.SH DESCRIPTION
.B minetestmapper
generates an overview image of a minetest map. This is a port of
the original minetestmapper.py to C++, that is both faster and
provides more functionality than the deprecated Python script.
.SH MANDATORY PARAMETERS
.TP
.BR \-i " " \fIworld_path\fR
Input world path.
.TP
.BR \-o " " \fIoutput_image\fR
Path to output image. (only PNG supported currently)
.SH OPTIONAL PARAMETERS
.TP
.BR \-\-bgcolor " " \fIcolor\fR
Background color of image, e.g. "--bgcolor #ffffff"
.TP
.BR \-\-scalecolor " " \fIcolor\fR
Color of scale, e.g. "--scalecolor #000000"
.TP
.BR \-\-playercolor " " \fIcolor\fR
Color of player indicators, e.g. "--playercolor #ff0000"
.TP
.BR \-\-origincolor " " \fIcolor\fR
Color of origin indicator, e.g. "--origincolor #ff0000"
.TP
.BR \-\-drawscale
Draw tick marks
.TP
.BR \-\-drawplayers
Draw player indicators
.TP
.BR \-\-draworigin
Draw origin indicator
.TP
.BR \-\-drawalpha
Allow nodes to be drawn with transparency
.TP
.BR \-\-noshading
Don't draw shading on nodes
.TP
.BR \-\-noemptyimage
Don't output anything when the image would be empty.
.TP
.BR \-\-min-y " " \fInumber\fR
Don't draw nodes below this y value, e.g. "--min-y -25"
.TP
.BR \-\-max-y " " \fInumber\fR
Don't draw nodes above this y value, e.g. "--max-y 75"
.TP
.BR \-\-backend " " \fIbackend\fR
Use specific map backend; supported: *sqlite3*, *leveldb*, *redis*, *postgresql*, e.g. "--backend leveldb"
.TP
.BR \-\-geometry " " \fIgeometry\fR
Limit area to specific geometry (*x:y+w+h* where x and y specify the lower left corner), e.g. "--geometry -800:-800+1600+1600"
.TP
.BR \-\-extent " " \fIextent\fR
Dont render the image, just print the extent of the map that would be generated, in the same format as the geometry above.
.TP
.BR \-\-zoom " " \fIfactor\fR
Zoom the image by using more than one pixel per node, e.g. "--zoom 4"
.TP
.BR \-\-colors " " \fIpath\fR
Forcefully set path to colors.txt file (it's autodetected otherwise), e.g. "--colors ../minetest/mycolors.txt"
.TP
.BR \-\-scales " " \fIedges\fR
Draw scales on specified image edges (letters *t b l r* meaning top, bottom, left and right), e.g. "--scales tbr"
.SH MORE INFORMATION
Website: https://github.com/minetest/minetestmapper
.SH MAN PAGE AUTHOR
Daniel Moerner

View File

@ -1,6 +1,3 @@
#include <stdexcept>
#include <sstream>
#include "util.h"
inline std::string trim(const std::string &s)
@ -26,15 +23,11 @@ inline std::string trim(const std::string &s)
return s.substr(front, back - front);
}
#define EOFCHECK() do { \
if (is.eof()) { \
std::ostringstream oss; \
oss << "Setting '" << name << "' not found."; \
throw std::runtime_error(oss.str()); \
} \
} while(0)
#define EOFCHECK() \
if(is.eof()) \
throw std::runtime_error(((std::string) "Setting '") + name + "' not found");
std::string read_setting(const std::string &name, std::istream &is)
std::string get_setting(std::string name, std::istream &is)
{
char c;
char s[256];

10
util.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _UTIL_H
#define _UTIL_H
#include <string>
#include <stdexcept>
#include <fstream>
std::string get_setting(std::string name, std::istream &is);
#endif // _UTIL_H

View File

@ -1,73 +0,0 @@
#!/bin/bash -e
#######
# this expects an env similar to what minetest's buildbot uses
# extradll_path will typically contain libgcc, libstdc++ and libpng
toolchain_file=
toolchain_file64=
libgd_dir=
libgd_dir64=
zlib_dir=
zlib_dir64=
sqlite_dir=
sqlite_dir64=
leveldb_dir=
leveldb_dir64=
extradll_path=
extradll_path64=
#######
[ -f ./CMakeLists.txt ] || exit 1
if [ "$1" == "32" ]; then
:
elif [ "$1" == "64" ]; then
toolchain_file=$toolchain_file64
libgd_dir=$libgd_dir64
zlib_dir=$zlib_dir64
sqlite_dir=$sqlite_dir64
leveldb_dir=$leveldb_dir64
extradll_path=$extradll_path64
else
echo "Usage: $0 <32 / 64>"
exit 1
fi
cmake . \
-DCMAKE_INSTALL_PREFIX=/tmp \
-DCMAKE_TOOLCHAIN_FILE=$toolchain_file \
-DCMAKE_EXE_LINKER_FLAGS="-s" \
\
-DENABLE_LEVELDB=1 \
\
-DLIBGD_INCLUDE_DIR=$libgd_dir/include \
-DLIBGD_LIBRARY=$libgd_dir/lib/libgd.dll.a \
\
-DZLIB_INCLUDE_DIR=$zlib_dir/include \
-DZLIB_LIBRARY=$zlib_dir/lib/libz.dll.a \
\
-DSQLITE3_INCLUDE_DIR=$sqlite_dir/include \
-DSQLITE3_LIBRARY=$sqlite_dir/lib/libsqlite3.dll.a \
\
-DLEVELDB_INCLUDE_DIR=$leveldb_dir/include \
-DLEVELDB_LIBRARY=$leveldb_dir/lib/libleveldb.dll.a
make -j4
mkdir pack
cp -p \
AUTHORS colors.txt COPYING README.rst \
minetestmapper.exe \
$libgd_dir/bin/libgd-3.dll \
$zlib_dir/bin/zlib1.dll \
$sqlite_dir/bin/libsqlite3-0.dll \
$leveldb_dir/bin/libleveldb.dll \
$extradll_path/*.dll \
pack/
zipfile=minetestmapper-win$1.zip
(cd pack; zip -9r ../$zipfile *)
make clean
rm -r pack CMakeCache.txt
echo "Done."

View File

@ -1,8 +1,17 @@
#!/bin/bash -e
CXX=g++-6
[ $CC == "clang" ] && CXX=clang-3.8
export CXX
mkdir -p travisbuild
cd travisbuild
cmake .. \
-DENABLE_LEVELDB=1
cmake \
-DENABLE_LEVELDB=1 \
-DLEVELDB_LIBRARY=../libleveldb/lib/libleveldb.so \
-DLEVELDB_INCLUDE_DIR=../libleveldb/include \
..
make -j2