Codebase list minetestmapper / 49cc10b3-a940-4e46-ba83-29787fb9403b/upstream
Import upstream version 20200328+git20210329.1.fd4c5dd Debian Janitor 2 years ago
27 changed file(s) with 438 addition(s) and 363 deletion(s). Raw diff Collapse all Expand all
0 arch:
1 - amd64
2 - ppc64le
03 language: cpp
14 compiler:
25 - gcc
1010 return data[0] << 8 | data[1];
1111 }
1212
13 static int readBlockContent(const unsigned char *mapData, u8 version, unsigned int datapos)
13 static inline uint16_t readBlockContent(const unsigned char *mapData,
14 u8 contentWidth, unsigned int datapos)
1415 {
15 if (version >= 24) {
16 if (contentWidth == 2) {
1617 size_t index = datapos << 1;
1718 return (mapData[index] << 8) | mapData[index + 1];
18 } else if (version >= 20) {
19 if (mapData[datapos] <= 0x80)
20 return mapData[datapos];
19 } else {
20 u8 param = mapData[datapos];
21 if (param <= 0x7f)
22 return param;
2123 else
22 return (int(mapData[datapos]) << 4) | (int(mapData[datapos + 0x2000]) >> 4);
24 return (param << 4) | (mapData[datapos + 0x2000] >> 4);
2325 }
24 std::ostringstream oss;
25 oss << "Unsupported map version " << version;
26 throw std::runtime_error(oss.str());
2726 }
2827
2928 BlockDecoder::BlockDecoder()
3837 m_nameMap.clear();
3938
4039 m_version = 0;
40 m_contentWidth = 0;
4141 m_mapData = ustring();
4242 }
4343
4949
5050 uint8_t version = data[0];
5151 //uint8_t flags = data[1];
52 if (version < 22) {
53 std::ostringstream oss;
54 oss << "Unsupported map version " << (int)version;
55 throw std::runtime_error(oss.str());
56 }
5257 m_version = version;
5358
5459 size_t dataOffset = 0;
5560 if (version >= 27)
56 dataOffset = 6;
57 else if (version >= 22)
5861 dataOffset = 4;
5962 else
6063 dataOffset = 2;
64
65 uint8_t contentWidth = data[dataOffset];
66 dataOffset++;
67 uint8_t paramsWidth = data[dataOffset];
68 dataOffset++;
69 if (contentWidth != 1 && contentWidth != 2)
70 throw std::runtime_error("unsupported map version (contentWidth)");
71 if (paramsWidth != 2)
72 throw std::runtime_error("unsupported map version (paramsWidth)");
73 m_contentWidth = contentWidth;
74
6175
6276 ZlibDecompressor decompressor(data, length);
6377 decompressor.setSeekPos(dataOffset);
6680 dataOffset = decompressor.seekPos();
6781
6882 // Skip unused data
69 if (version <= 21)
70 dataOffset += 2;
7183 if (version == 23)
7284 dataOffset += 1;
7385 if (version == 24) {
91103 dataOffset += 4; // Skip timestamp
92104
93105 // Read mapping
94 if (version >= 22) {
106 {
95107 dataOffset++; // mapping version
96108 uint16_t numMappings = readU16(data + dataOffset);
97109 dataOffset += 2;
113125
114126 // Node timers
115127 if (version >= 25) {
116 dataOffset++;
128 uint8_t timerLength = data[dataOffset++];
117129 uint16_t numTimers = readU16(data + dataOffset);
118130 dataOffset += 2;
119 dataOffset += numTimers * 10;
131 dataOffset += numTimers * timerLength;
120132 }
121133 }
122134
126138 return m_nameMap.empty();
127139 }
128140
129 std::string BlockDecoder::getNode(u8 x, u8 y, u8 z) const
141 const static std::string empty;
142
143 const std::string &BlockDecoder::getNode(u8 x, u8 y, u8 z) const
130144 {
131145 unsigned int position = x + (y << 4) + (z << 8);
132 int content = readBlockContent(m_mapData.c_str(), m_version, position);
146 uint16_t content = readBlockContent(m_mapData.c_str(), m_contentWidth, position);
133147 if (content == m_blockAirId || content == m_blockIgnoreId)
134 return "";
148 return empty;
135149 NameMap::const_iterator it = m_nameMap.find(content);
136150 if (it == m_nameMap.end()) {
137151 std::cerr << "Skipping node with invalid ID." << std::endl;
138 return "";
152 return empty;
139153 }
140154 return it->second;
141155 }
0 cmake_minimum_required(VERSION 3.5)
1
02 project(minetestmapper CXX)
1 cmake_minimum_required(VERSION 2.6)
2 cmake_policy(SET CMP0003 NEW)
33
44 set(VERSION_MAJOR 1)
55 set(VERSION_MINOR 0)
4545 endif()
4646
4747 #set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
48 find_package(PkgConfig)
49 include(FindPackageHandleStandardArgs)
5048
5149 # Libraries: gd
5250
6058
6159 # Libraries: zlib
6260
63 find_library(ZLIB_LIBRARY z)
64 find_path(ZLIB_INCLUDE_DIR zlib.h)
65 message (STATUS "zlib library: ${ZLIB_LIBRARY}")
66 message (STATUS "zlib headers: ${ZLIB_INCLUDE_DIR}")
67 if(NOT ZLIB_LIBRARY OR NOT ZLIB_INCLUDE_DIR)
68 message(FATAL_ERROR "zlib not found!")
69 endif(NOT ZLIB_LIBRARY OR NOT ZLIB_INCLUDE_DIR)
61 find_package(ZLIB REQUIRED)
7062
7163 # Libraries: sqlite3
7264
7365 find_library(SQLITE3_LIBRARY sqlite3)
74 find_path(SQLITE3_INCLUDE_DIR zlib.h)
66 find_path(SQLITE3_INCLUDE_DIR sqlite3.h)
7567 message (STATUS "sqlite3 library: ${SQLITE3_LIBRARY}")
7668 message (STATUS "sqlite3 headers: ${SQLITE3_INCLUDE_DIR}")
7769 if(NOT SQLITE3_LIBRARY OR NOT SQLITE3_INCLUDE_DIR)
1616
1717 // ARGB but with inverted alpha
1818
19 static inline int color2int(Color c)
19 static inline int color2int(const Color &c)
2020 {
2121 u8 a = (255 - c.a) * gdAlphaMax / 255;
2222 return (a << 24) | (c.r << 16) | (c.g << 8) | c.b;
3434 return c2;
3535 }
3636
37 #ifndef NDEBUG
3738 static inline void check_bounds(int x, int y, int width, int height)
3839 {
3940 if(x < 0 || x >= width) {
4950 throw std::out_of_range(oss.str());
5051 }
5152 }
53 #endif
5254
5355
5456 Image::Image(int width, int height) :
5557 m_width(width), m_height(height), m_image(NULL)
5658 {
59 SIZECHECK(0, 0);
5760 m_image = gdImageCreateTrueColor(m_width, m_height);
5861 }
5962
0 /*
1 * =====================================================================
2 * Version: 1.0
3 * Created: 25.08.2012 10:55:27
4 * Author: Miroslav Bendík
5 * Company: LinuxOS.sk
6 * =====================================================================
7 */
0 #include <cstring>
81
92 #include "PixelAttributes.h"
10 #include <cstring>
113
124 PixelAttributes::PixelAttributes():
135 m_width(0)
88 #include "PlayerAttributes.h"
99 #include "util.h"
1010
11 using namespace std;
12
1311 PlayerAttributes::PlayerAttributes(const std::string &worldDir)
1412 {
15 std::ifstream ifs((worldDir + "world.mt").c_str());
13 std::ifstream ifs(worldDir + "world.mt");
1614 if (!ifs.good())
1715 throw std::runtime_error("Failed to read world.mt");
1816 std::string backend = read_setting_default("player_backend", ifs, "files");
3836 if (ent->d_name[0] == '.')
3937 continue;
4038
41 string path = playersPath + PATH_SEPARATOR + ent->d_name;
42 ifstream in(path.c_str());
39 std::string path = playersPath + PATH_SEPARATOR + ent->d_name;
40 std::ifstream in(path);
4341 if(!in.good())
4442 continue;
4543
46 string name, position;
44 std::string name, position;
4745 name = read_setting("name", in);
4846 in.seekg(0);
4947 position = read_setting("position", in);
5048
5149 Player player;
52 istringstream iss(position);
50 std::istringstream iss(position);
5351 char tmp;
5452 iss >> tmp; // '('
5553 iss >> player.x;
120118
121119 /**********/
122120
123 PlayerAttributes::Players::iterator PlayerAttributes::begin()
121 PlayerAttributes::Players::const_iterator PlayerAttributes::begin() const
124122 {
125 return m_players.begin();
123 return m_players.cbegin();
126124 }
127125
128 PlayerAttributes::Players::iterator PlayerAttributes::end()
126 PlayerAttributes::Players::const_iterator PlayerAttributes::end() const
129127 {
130 return m_players.end();
128 return m_players.cend();
131129 }
132130
22
33 .. image:: https://travis-ci.org/minetest/minetestmapper.svg?branch=master
44 :target: https://travis-ci.org/minetest/minetestmapper
5
6 Minetestmapper generates an overview image from a Minetest map.
57
68 A port of minetestmapper.py to C++ from https://github.com/minetest/minetest/tree/master/util.
79 This version is both faster and provides more features than the now deprecated Python script.
1113
1214 * libgd
1315 * sqlite3
14 * LevelDB (optional, set ENABLE_LEVELDB=1 in CMake to enable)
15 * hiredis library (optional, set ENABLE_REDIS=1 in CMake to enable)
16 * Postgres libraries (optional, set ENABLE_POSTGRES=1 in CMake to enable)
16 * LevelDB (optional)
17 * hiredis (optional)
18 * Postgres libraries (optional)
1719
18 e.g. on Debian:
19 ^^^^^^^^^^^^^^^
20 on Debian:
21 ^^^^^^^^^^
2022
21 sudo apt-get install libgd-dev libsqlite3-dev libleveldb-dev libhiredis-dev libpq-dev
23 sudo apt install libgd-dev libsqlite3-dev libleveldb-dev libhiredis-dev libpq-dev
24
25 on openSUSE:
26 ^^^^^^^^^^^^
27
28 sudo zypper install gd-devel sqlite3-devel leveldb-devel hiredis-devel postgresql-devel postgresql-server-devel
2229
2330 Windows
2431 ^^^^^^^
3643 ::
3744
3845 cmake . -DENABLE_LEVELDB=1
39 make -j2
46 make -j$(nproc)
4047
4148 Usage
4249 -----
1212 #include "config.h"
1313 #include "PlayerAttributes.h"
1414 #include "BlockDecoder.h"
15 #include "Image.h"
1516 #include "util.h"
17
1618 #include "db-sqlite3.h"
1719 #if USE_POSTGRESQL
1820 #include "db-postgresql.h"
2325 #if USE_REDIS
2426 #include "db-redis.h"
2527 #endif
26
27 using namespace std;
2828
2929 template<typename T>
3030 static inline T mymax(T a, T b)
5353 static inline unsigned int colorSafeBounds (int channel)
5454 {
5555 return mymin(mymax(channel, 0), 255);
56 }
57
58 static Color parseColor(const std::string &color)
59 {
60 if (color.length() != 7)
61 throw std::runtime_error("Color needs to be 7 characters long");
62 if (color[0] != '#')
63 throw std::runtime_error("Color needs to begin with #");
64 unsigned long col = strtoul(color.c_str() + 1, NULL, 16);
65 u8 b, g, r;
66 b = col & 0xff;
67 g = (col >> 8) & 0xff;
68 r = (col >> 16) & 0xff;
69 return Color(r, g, b);
5670 }
5771
5872 static Color mixColors(Color a, Color b)
138152 m_scales = flags;
139153 }
140154
141 Color TileGenerator::parseColor(const std::string &color)
142 {
143 Color parsed;
144 if (color.length() != 7)
145 throw std::runtime_error("Color needs to be 7 characters long");
146 if (color[0] != '#')
147 throw std::runtime_error("Color needs to begin with #");
148 unsigned long col = strtoul(color.c_str() + 1, NULL, 16);
149 parsed.b = col & 0xff;
150 parsed.g = (col >> 8) & 0xff;
151 parsed.r = (col >> 16) & 0xff;
152 parsed.a = 255;
153 return parsed;
154 }
155
156155 void TileGenerator::setDrawOrigin(bool drawOrigin)
157156 {
158157 m_drawOrigin = drawOrigin;
213212
214213 void TileGenerator::parseColorsFile(const std::string &fileName)
215214 {
216 ifstream in;
217 in.open(fileName.c_str(), ifstream::in);
218 if (!in.is_open())
215 std::ifstream in(fileName);
216 if (!in.good())
219217 throw std::runtime_error("Specified colors file could not be found");
220218 parseColorsStream(in);
221219 }
222220
223221 void TileGenerator::printGeometry(const std::string &input)
224222 {
225 string input_path = input;
223 std::string input_path = input;
226224 if (input_path[input.length() - 1] != PATH_SEPARATOR) {
227225 input_path += PATH_SEPARATOR;
228226 }
248246
249247 void TileGenerator::generate(const std::string &input, const std::string &output)
250248 {
251 string input_path = input;
249 std::string input_path = input;
252250 if (input_path[input.length() - 1] != PATH_SEPARATOR) {
253251 input_path += PATH_SEPARATOR;
254252 }
304302 std::cerr << "Failed to parse color entry '" << line << "'" << std::endl;
305303 continue;
306304 }
307
308 ColorEntry color(r, g, b, a, t);
309 m_colorMap[name] = color;
305
306 m_colorMap[name] = ColorEntry(r, g, b, a, t);
310307 }
311308 }
312309
329326 void TileGenerator::openDb(const std::string &input)
330327 {
331328 std::string backend = m_backend;
332 if(backend == "") {
333 std::ifstream ifs((input + "/world.mt").c_str());
329 if (backend == "") {
330 std::ifstream ifs(input + "/world.mt");
334331 if(!ifs.good())
335 throw std::runtime_error("Failed to read world.mt");
336 backend = read_setting("backend", ifs);
332 throw std::runtime_error("Failed to open world.mt");
333 backend = read_setting_default("backend", ifs, "sqlite3");
337334 ifs.close();
338335 }
339336
585582 if (m_readPixels.get(x, z))
586583 continue;
587584 int imageX = xBegin + x;
585 auto &attr = m_blockPixelAttributes.attribute(15 - z, xBegin + x);
588586
589587 for (int y = maxY; y >= minY; --y) {
590 string name = blk.getNode(x, y, z);
591 if (name == "")
588 const std::string &name = blk.getNode(x, y, z);
589 if (name.empty())
592590 continue;
593591 ColorMap::const_iterator it = m_colorMap.find(name);
594592 if (it == m_colorMap.end()) {
595593 m_unknownNodes.insert(name);
596594 continue;
597595 }
598 const Color c = it->second.to_color();
596
597 Color c = it->second.toColor();
598 if (c.a == 0)
599 continue; // node is fully invisible
599600 if (m_drawAlpha) {
600 if (m_color[z][x].a == 0)
601 m_color[z][x] = c; // first visible time, no color mixing
602 else
603 m_color[z][x] = mixColors(m_color[z][x], c);
604 if(m_color[z][x].a < 0xff) {
605 // near thickness value to thickness of current node
606 m_thickness[z][x] = (m_thickness[z][x] + it->second.t) / 2.0;
601 if (m_color[z][x].a != 0)
602 c = mixColors(m_color[z][x], c);
603 if (c.a < 255) {
604 // remember color and near thickness value
605 m_color[z][x] = c;
606 m_thickness[z][x] = (m_thickness[z][x] + it->second.t) / 2;
607607 continue;
608608 }
609609 // color became opaque, draw it
610 setZoomed(imageX, imageY, m_color[z][x]);
611 m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
610 setZoomed(imageX, imageY, c);
611 attr.thickness = m_thickness[z][x];
612612 } else {
613 setZoomed(imageX, imageY, c.noAlpha());
613 c.a = 255;
614 setZoomed(imageX, imageY, c);
614615 }
615616 m_readPixels.set(x, z);
616617
617618 // do this afterwards so we can record height values
618619 // inside transparent nodes (water) too
619620 if (!m_readInfo.get(x, z)) {
620 m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y;
621 attr.height = pos.y * 16 + y;
621622 m_readInfo.set(x, z);
622623 }
623624 break;
639640 if (m_readPixels.get(x, z))
640641 continue;
641642 int imageX = xBegin + x;
643 auto &attr = m_blockPixelAttributes.attribute(15 - z, xBegin + x);
642644
643645 // set color since it wasn't done in renderMapBlock()
644646 setZoomed(imageX, imageY, m_color[z][x]);
645647 m_readPixels.set(x, z);
646 m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
648 attr.thickness = m_thickness[z][x];
647649 }
648650 }
649651 }
650652
651653 void TileGenerator::renderShading(int zPos)
652654 {
655 auto &a = m_blockPixelAttributes;
653656 int zBegin = (m_zMax - zPos) * 16;
654657 for (int z = 0; z < 16; ++z) {
655658 int imageY = zBegin + z;
657660 continue;
658661 for (int x = 0; x < m_mapWidth; ++x) {
659662 if(
660 !m_blockPixelAttributes.attribute(z, x).valid_height() ||
661 !m_blockPixelAttributes.attribute(z, x - 1).valid_height() ||
662 !m_blockPixelAttributes.attribute(z - 1, x).valid_height()
663 !a.attribute(z, x).valid_height() ||
664 !a.attribute(z, x - 1).valid_height() ||
665 !a.attribute(z - 1, x).valid_height()
663666 )
664667 continue;
665668
666669 // calculate shadow to apply
667 int y = m_blockPixelAttributes.attribute(z, x).height;
668 int y1 = m_blockPixelAttributes.attribute(z, x - 1).height;
669 int y2 = m_blockPixelAttributes.attribute(z - 1, x).height;
670 int y = a.attribute(z, x).height;
671 int y1 = a.attribute(z, x - 1).height;
672 int y2 = a.attribute(z - 1, x).height;
670673 int d = ((y - y1) + (y - y2)) * 12;
674
671675 if (m_drawAlpha) { // less visible shadow with increasing "thickness"
672 double t = m_blockPixelAttributes.attribute(z, x).thickness * 1.2;
673 d *= 1.0 - mymin(t, 255.0) / 255.0;
674 }
676 float t = a.attribute(z, x).thickness * 1.2f;
677 t = mymin(t, 255.0f);
678 d *= 1.0f - t / 255.0f;
679 }
680
675681 d = mymin(d, 36);
676682
683 // apply shadow/light by just adding to it pixel values
677684 Color c = m_image->getPixel(getImageX(x), getImageY(imageY));
678685 c.r = colorSafeBounds(c.r + d);
679686 c.g = colorSafeBounds(c.g + d);
681688 setZoomed(x, imageY, c);
682689 }
683690 }
684 m_blockPixelAttributes.scroll();
691 a.scroll();
685692 }
686693
687694 void TileGenerator::renderScale()
0 /*
1 * =====================================================================
2 * Version: 1.0
3 * Created: 18.09.2012 10:20:47
4 * Author: Miroslav Bendík
5 * Company: LinuxOS.sk
6 * =====================================================================
7 */
8
90 #include <zlib.h>
101 #include <stdint.h>
112 #include "ZlibDecompressor.h"
3728 const std::size_t size = m_size - m_seekPos;
3829
3930 ustring buffer;
40 const size_t BUFSIZE = 128 * 1024;
41 uint8_t temp_buffer[BUFSIZE];
31 constexpr size_t BUFSIZE = 128 * 1024;
32 unsigned char temp_buffer[BUFSIZE];
4233
4334 z_stream strm;
4435 strm.zalloc = Z_NULL;
4738 strm.next_in = Z_NULL;
4839 strm.avail_in = size;
4940
50 if (inflateInit(&strm) != Z_OK) {
41 if (inflateInit(&strm) != Z_OK)
5142 throw DecompressError();
52 }
5343
5444 strm.next_in = const_cast<unsigned char *>(data);
5545 int ret = 0;
5747 strm.avail_out = BUFSIZE;
5848 strm.next_out = temp_buffer;
5949 ret = inflate(&strm, Z_NO_FLUSH);
60 buffer += ustring(reinterpret_cast<unsigned char *>(temp_buffer), BUFSIZE - strm.avail_out);
50 buffer.append(temp_buffer, BUFSIZE - strm.avail_out);
6151 } while (ret == Z_OK);
62 if (ret != Z_STREAM_END) {
52 if (ret != Z_STREAM_END)
6353 throw DecompressError();
64 }
54
6555 m_seekPos += strm.next_in - data;
6656 (void)inflateEnd(&strm);
6757
+0
-132
autogenerating-colors.txt less more
0 ==FILE== mods/dumpnodes/init.lua
1 local function nd_get_tiles(nd)
2 return nd.tiles or nd.tile_images
3 end
4
5 local function nd_get_tile(nd, n)
6 local tile = nd_get_tiles(nd)[n]
7 if type(tile) == 'table' then
8 tile = tile.name
9 end
10 return tile
11 end
12
13 local function pairs_s(dict)
14 local keys = {}
15 for k in pairs(dict) do
16 table.insert(keys, k)
17 end
18 table.sort(keys)
19 return ipairs(keys)
20 end
21
22 minetest.register_chatcommand("dumpnodes", {
23 params = "",
24 description = "",
25 func = function(player, param)
26 local n = 0
27 local ntbl = {}
28 for _, nn in pairs_s(minetest.registered_nodes) do
29 local nd = minetest.registered_nodes[nn]
30 local prefix, name = nn:match('(.*):(.*)')
31 if prefix == nil or name == nil then
32 print("ignored(1): " .. nn)
33 else
34 if ntbl[prefix] == nil then
35 ntbl[prefix] = {}
36 end
37 ntbl[prefix][name] = true
38 end
39 end
40 local out, err = io.open('nodes.txt', 'wb')
41 if not out then
42 return true, "io.open(): " .. err
43 end
44 for _, prefix in pairs_s(ntbl) do
45 out:write('# ' .. prefix .. '\n')
46 for _, name in pairs_s(ntbl[prefix]) do
47 local nn = prefix .. ":" .. name
48 local nd = minetest.registered_nodes[nn]
49 if nd.drawtype == 'airlike' or nd_get_tiles(nd) == nil then
50 print("ignored(2): " .. nn)
51 else
52 local tl = nd_get_tile(nd, 1)
53 tl = (tl .. '^'):match('(.-)^') -- strip modifiers
54 out:write(nn .. ' ' .. tl .. '\n')
55 n = n + 1
56 end
57 end
58 out:write('\n')
59 end
60 out:close()
61 return true, n .. " nodes dumped."
62 end,
63 })
64 ==FILE== avgcolor.py
65 #!/usr/bin/env python
66 import sys
67 from math import sqrt
68 from PIL import Image
69
70 if len(sys.argv) < 2:
71 print("Prints average color (RGB) of input image")
72 print("Usage: %s <input>" % sys.argv[0])
73 exit(1)
74
75 inp = Image.open(sys.argv[1]).convert('RGBA')
76 ind = inp.load()
77
78 cl = ([], [], [])
79 for x in range(inp.size[0]):
80 for y in range(inp.size[1]):
81 px = ind[x, y]
82 if px[3] < 128: continue # alpha
83 cl[0].append(px[0]**2)
84 cl[1].append(px[1]**2)
85 cl[2].append(px[2]**2)
86
87 if len(cl[0]) == 0:
88 print("Didn't find average color for %s" % sys.argv[1], file=sys.stderr)
89 print("0 0 0")
90 else:
91 cl = tuple(sqrt(sum(x)/len(x)) for x in cl)
92 print("%d %d %d" % cl)
93 ==SCRIPT==
94 #!/bin/bash -e
95 AVGCOLOR_PATH=/path/to/avgcolor.py
96 GAME_PATH=/path/to/minetest_game
97 MODS_PATH= # path to "mods" folder, only set if you have loaded mods
98 NODESTXT_PATH=./nodes.txt
99 COLORSTXT_PATH=./colors.txt
100
101 while read -r line; do
102 set -- junk $line; shift
103 if [[ -z "$1" || $1 == "#" ]]; then
104 echo "$line"; continue
105 fi
106 tex=$(find $GAME_PATH -type f -name "$2")
107 [[ -z "$tex" && -n "$MODS_PATH" ]] && tex=$(find $MODS_PATH -type f -name "$2")
108 if [ -z "$tex" ]; then
109 echo "skip $1: texture not found" >&2
110 continue
111 fi
112 echo "$1" $(python $AVGCOLOR_PATH "$tex")
113 echo "ok $1" >&2
114 done < $NODESTXT_PATH > $COLORSTXT_PATH
115 # Use nicer colors for water and lava:
116 sed -re 's/^default:((river_)?water_(flowing|source)) [0-9 ]+$/default:\1 39 66 106 128 224/g' $COLORSTXT_PATH -i
117 sed -re 's/^default:(lava_(flowing|source)) [0-9 ]+$/default:\1 255 100 0/g' $COLORSTXT_PATH -i
118 # Add transparency to glass nodes and xpanes:
119 sed -re 's/^default:(.*glass) ([0-9 ]+)$/default:\1 \2 64 16/g' $COLORSTXT_PATH -i
120 sed -re 's/^doors:(.*glass[^ ]*) ([0-9 ]+)$/doors:\1 \2 64 16/g' $COLORSTXT_PATH -i
121 sed -re 's/^xpanes:(.*(pane|bar)[^ ]*) ([0-9 ]+)$/xpanes:\1 \3 64 16/g' $COLORSTXT_PATH -i
122 # Delete some usually hidden nodes:
123 sed '/^doors:hidden /d' $COLORSTXT_PATH -i
124 sed '/^fireflies:firefly /d' $COLORSTXT_PATH -i
125 sed '/^butterflies:butterfly_/d' $COLORSTXT_PATH -i
126 ==INSTRUCTIONS==
127 1) Make sure avgcolors.py works (outputs the usage instructions when run)
128 2) Add the dumpnodes mod to Minetest
129 3) Create a world and load dumpnodes & all mods you want to generate colors for
130 4) Execute /dumpnodes ingame
131 5) Run the script to generate colors.txt (make sure to adjust the PATH variables at the top)
0 #ifndef BLOCKDECODER_H
1 #define BLOCKDECODER_H
0 #pragma once
21
32 #include <unordered_map>
43
1110 void reset();
1211 void decode(const ustring &data);
1312 bool isEmpty() const;
14 std::string getNode(u8 x, u8 y, u8 z) const; // returns "" for air, ignore and invalid nodes
13 // returns "" for air, ignore and invalid nodes
14 const std::string &getNode(u8 x, u8 y, u8 z) const;
1515
1616 private:
17 typedef std::unordered_map<int, std::string> NameMap;
17 typedef std::unordered_map<uint16_t, std::string> NameMap;
1818 NameMap m_nameMap;
1919 int m_blockAirId;
2020 int m_blockIgnoreId;
2121
22 u8 m_version;
22 u8 m_version, m_contentWidth;
2323 ustring m_mapData;
2424 };
25
26 #endif // BLOCKDECODER_H
0 #ifndef IMAGE_HEADER
1 #define IMAGE_HEADER
0 #pragma once
21
32 #include "types.h"
43 #include <string>
87 Color() : r(0), g(0), b(0), a(0) {};
98 Color(u8 r, u8 g, u8 b) : r(r), g(g), b(b), a(255) {};
109 Color(u8 r, u8 g, u8 b, u8 a) : r(r), g(g), b(b), a(a) {};
11 inline Color noAlpha() const { return Color(r, g, b); }
1210
1311 u8 r, g, b, a;
1412 };
1715 public:
1816 Image(int width, int height);
1917 ~Image();
18
19 Image(const Image&) = delete;
20 Image& operator=(const Image&) = delete;
2021
2122 void setPixel(int x, int y, const Color &c);
2223 Color getPixel(int x, int y);
2728 void save(const std::string &filename);
2829
2930 private:
30 Image(const Image&);
31
3231 int m_width, m_height;
3332 gdImagePtr m_image;
3433 };
35
36 #endif // IMAGE_HEADER
0 /*
1 * =====================================================================
2 * Version: 1.0
3 * Created: 25.08.2012 10:55:29
4 * Author: Miroslav Bendík
5 * Company: LinuxOS.sk
6 * =====================================================================
7 */
0 #pragma once
81
9 #ifndef PIXELATTRIBUTES_H_ADZ35GYF
10 #define PIXELATTRIBUTES_H_ADZ35GYF
11
12 #include <limits>
13 #include <stdint.h>
2 #include <climits>
3 #include <cstdint>
144 #include "config.h"
155
166 struct PixelAttribute {
17 PixelAttribute(): height(std::numeric_limits<int>::min()), thickness(0) {};
18 int height;
7 PixelAttribute(): height(INT16_MIN), thickness(0) {};
8 int16_t height;
199 uint8_t thickness;
2010 inline bool valid_height() {
21 return height != std::numeric_limits<int>::min();
11 return height != INT16_MIN;
2212 }
2313 };
2414
2919 virtual ~PixelAttributes();
3020 void setWidth(int width);
3121 void scroll();
32 inline PixelAttribute &attribute(int z, int x) { return m_pixelAttributes[z + 1][x + 1]; };
22 inline PixelAttribute &attribute(int z, int x) {
23 return m_pixelAttributes[z + 1][x + 1];
24 };
3325
3426 private:
3527 void freeAttributes();
4436 PixelAttribute *m_pixelAttributes[BLOCK_SIZE + 2]; // 1px gradient + empty
4537 int m_width;
4638 };
47
48 #endif /* end of include guard: PIXELATTRIBUTES_H_ADZ35GYF */
49
0 #ifndef PLAYERATTRIBUTES_H_D7THWFVV
1 #define PLAYERATTRIBUTES_H_D7THWFVV
0 #pragma once
21
32 #include <list>
43 #include <string>
1514 typedef std::list<Player> Players;
1615
1716 PlayerAttributes(const std::string &worldDir);
18 Players::iterator begin();
19 Players::iterator end();
17 Players::const_iterator begin() const;
18 Players::const_iterator end() const;
2019
2120 private:
2221 void readFiles(const std::string &playersPath);
2423
2524 Players m_players;
2625 };
27
28 #endif /* end of include guard: PLAYERATTRIBUTES_H_D7THWFVV */
29
00 #ifndef TILEGENERATOR_HEADER
11 #define TILEGENERATOR_HEADER
22
3 #include <iosfwd>
3 #include <iostream>
44 #include <map>
55 #include <set>
6 #include <config.h>
76 #include <unordered_map>
87 #include <unordered_set>
9 #include <stdint.h>
8 #include <cstdint>
109 #include <string>
1110
1211 #include "PixelAttributes.h"
13 #include "BlockDecoder.h"
1412 #include "Image.h"
1513 #include "db.h"
1614 #include "types.h"
15
16 class BlockDecoder;
17 class Image;
1718
1819 enum {
1920 SCALE_TOP = (1 << 0),
3031 };
3132
3233 struct ColorEntry {
33 ColorEntry(): r(0), g(0), b(0), a(0), t(0) {};
34 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) {};
35 inline Color to_color() const { return Color(r, g, b, a); }
36 uint8_t r, g, b, a, t;
34 ColorEntry() : r(0), g(0), b(0), a(0), t(0) {};
35 ColorEntry(uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t t) :
36 r(r), g(g), b(b), a(a), t(t) {};
37 inline Color toColor() const { return Color(r, g, b, a); }
38 uint8_t r, g, b, a; // Red, Green, Blue, Alpha
39 uint8_t t; // "thickness" value
3740 };
3841
3942 struct BitmapThing { // 16x16 bitmap
7275 void setScaleColor(const std::string &scaleColor);
7376 void setOriginColor(const std::string &originColor);
7477 void setPlayerColor(const std::string &playerColor);
75 Color parseColor(const std::string &color);
7678 void setDrawOrigin(bool drawOrigin);
7779 void setDrawPlayers(bool drawPlayers);
7880 void setDrawScale(bool drawScale);
0 /*
1 * =====================================================================
2 * Version: 1.0
3 * Created: 18.09.2012 10:20:51
4 * Author: Miroslav Bendík
5 * Company: LinuxOS.sk
6 * =====================================================================
7 */
8
9 #ifndef ZLIBDECOMPRESSOR_H_ZQL1PN8Q
10 #define ZLIBDECOMPRESSOR_H_ZQL1PN8Q
0 #pragma once
111
122 #include <cstdlib>
133 #include <string>
3020 const unsigned char *m_data;
3121 std::size_t m_seekPos;
3222 std::size_t m_size;
33 }; /* ----- end of class ZlibDecompressor ----- */
34
35 #endif /* end of include guard: ZLIBDECOMPRESSOR_H_ZQL1PN8Q */
36
23 };
0 #ifndef DB_LEVELDB_HEADER
1 #define DB_LEVELDB_HEADER
0 #pragma once
21
32 #include "db.h"
43 #include <unordered_map>
2625 std::unordered_map<int16_t, std::vector<pos2d>> posCache;
2726 leveldb::DB *db;
2827 };
29
30 #endif // DB_LEVELDB_HEADER
0 #ifndef _DB_POSTGRESQL_H
1 #define _DB_POSTGRESQL_H
0 #pragma once
21
32 #include "db.h"
43 #include <libpq-fe.h>
3029 private:
3130 PGconn *db;
3231 };
33
34 #endif // _DB_POSTGRESQL_H
0 #ifndef DB_REDIS_HEADER
1 #define DB_REDIS_HEADER
0 #pragma once
21
32 #include "db.h"
43 #include <unordered_map>
3231 redisContext *ctx;
3332 std::string hash;
3433 };
35
36 #endif // DB_REDIS_HEADER
0 #ifndef _DB_SQLITE3_H
1 #define _DB_SQLITE3_H
0 #pragma once
21
32 #include "db.h"
43 #include <unordered_map>
3130 int16_t blockCachedZ = -10000;
3231 std::unordered_map<int16_t, BlockList> blockCache; // indexed by X
3332 };
34
35 #endif // _DB_SQLITE3_H
0 #ifndef DB_HEADER
1 #define DB_HEADER
0 #pragma once
21
3 #include <stdint.h>
4 #include <map>
2 #include <cstdint>
53 #include <list>
64 #include <vector>
75 #include <utility>
121119 * End black magic *
122120 *******************/
123121
124 #endif // DB_HEADER
0 #ifndef UTIL_H
1 #define UTIL_H
0 #pragma once
21
32 #include <string>
43 #include <fstream>
54
65 std::string read_setting(const std::string &name, std::istream &is);
76
8 inline std::string read_setting_default(const std::string &name, std::istream &is, const std::string &def)
9 {
10 try {
11 return read_setting(name, is);
12 } catch(const std::runtime_error &e) {
13 return def;
14 }
15 }
16
17 #endif // UTIL_H
7 std::string read_setting_default(const std::string &name, std::istream &is,
8 const std::string &def);
77 #include <string>
88 #include <sstream>
99 #include <stdexcept>
10 #include "cmake_config.h"
10 #include "config.h"
1111 #include "TileGenerator.h"
1212
1313 static void usage()
5757
5858 static bool file_exists(const std::string &path)
5959 {
60 std::ifstream ifs(path.c_str());
60 std::ifstream ifs(path);
6161 return ifs.is_open();
6262 }
6363
255255 generator.parseColorsFile(colors);
256256 generator.generate(input, output);
257257
258 } catch(std::runtime_error &e) {
258 } catch (const std::runtime_error &e) {
259259 std::cerr << "Exception: " << e.what() << std::endl;
260260 return 1;
261261 }
0 local function get_tile(tiles, n)
1 local tile = tiles[n]
2 if type(tile) == 'table' then
3 return tile.name
4 end
5 return tile
6 end
7
8 local function pairs_s(dict)
9 local keys = {}
10 for k in pairs(dict) do
11 keys[#keys+1] = k
12 end
13 table.sort(keys)
14 return ipairs(keys)
15 end
16
17 minetest.register_chatcommand("dumpnodes", {
18 description = "Dump node and texture list for use with minetestmapper",
19 func = function()
20 local ntbl = {}
21 for _, nn in pairs_s(minetest.registered_nodes) do
22 local prefix, name = nn:match('(.*):(.*)')
23 if prefix == nil or name == nil then
24 print("ignored(1): " .. nn)
25 else
26 if ntbl[prefix] == nil then
27 ntbl[prefix] = {}
28 end
29 ntbl[prefix][name] = true
30 end
31 end
32 local out, err = io.open(minetest.get_worldpath() .. "/nodes.txt", 'wb')
33 if not out then
34 return true, err
35 end
36 local n = 0
37 for _, prefix in pairs_s(ntbl) do
38 out:write('# ' .. prefix .. '\n')
39 for _, name in pairs_s(ntbl[prefix]) do
40 local nn = prefix .. ":" .. name
41 local nd = minetest.registered_nodes[nn]
42 local tiles = nd.tiles or nd.tile_images
43 if tiles == nil or nd.drawtype == 'airlike' then
44 print("ignored(2): " .. nn)
45 else
46 local tex = get_tile(tiles, 1)
47 tex = (tex .. '^'):match('%(*(.-)%)*^') -- strip modifiers
48 if tex:find("[combine", 1, true) then
49 tex = tex:match('.-=([^:]-)') -- extract first texture
50 end
51 out:write(nn .. ' ' .. tex .. '\n')
52 n = n + 1
53 end
54 end
55 out:write('\n')
56 end
57 out:close()
58 return true, n .. " nodes dumped."
59 end,
60 })
0 name = dumpnodes
1 description = minetestmapper development mod (node dumper)
0 #!/usr/bin/env python3
1 import sys
2 import os.path
3 import getopt
4 import re
5 from math import sqrt
6 try:
7 from PIL import Image
8 except:
9 print("Could not load image routines, install PIL ('pillow' on pypi)!", file=sys.stderr)
10 exit(1)
11
12 ############
13 ############
14 # Instructions for generating a colors.txt file for custom games and/or mods:
15 # 1) Add the dumpnodes mod to a Minetest world with the chosen game and mods enabled.
16 # 2) Join ingame and run the /dumpnodes chat command.
17 # 3) Run this script and poin it to the installation path of the game using -g,
18 # the path(s) where mods are stored using -m and the nodes.txt in your world folder.
19 # Example command line:
20 # ./util/generate_colorstxt.py --game /usr/share/minetest/games/minetest_game \
21 # -m ~/.minetest/mods ~/.minetest/worlds/my_world/nodes.txt
22 # 4) Copy the resulting colors.txt file to your world folder or to any other places
23 # and use it with minetestmapper's --colors option.
24 ###########
25 ###########
26
27 # minimal sed syntax, s|match|replace| and /match/d supported
28 REPLACEMENTS = [
29 # Delete some nodes that are usually hidden
30 r'/^fireflies:firefly /d',
31 r'/^butterflies:butterfly_/d',
32 # Nicer colors for water and lava
33 r's/^(default:(river_)?water_(flowing|source)) [0-9 ]+$/\1 39 66 106 128 224/',
34 r's/^(default:lava_(flowing|source)) [0-9 ]+$/\1 255 100 0/',
35 # Transparency for glass nodes and panes
36 r's/^(default:.*glass) ([0-9 ]+)$/\1 \2 64 16/',
37 r's/^(doors:.*glass[^ ]*) ([0-9 ]+)$/\1 \2 64 16/',
38 r's/^(xpanes:.*(pane|bar)[^ ]*) ([0-9 ]+)$/\1 \3 64 16/',
39 ]
40
41 def usage():
42 print("Usage: generate_colorstxt.py [options] [input file] [output file]")
43 print("If not specified the input file defaults to ./nodes.txt and the output file to ./colors.txt")
44 print(" -g / --game <folder>\t\tSet path to the game (for textures), required")
45 print(" -m / --mods <folder>\t\tAdd search path for mod textures")
46 print(" --replace <file>\t\tLoad replacements from file (ADVANCED)")
47
48 def collect_files(path):
49 dirs = []
50 with os.scandir(path) as it:
51 for entry in it:
52 if entry.name[0] == '.': continue
53 if entry.is_dir():
54 dirs.append(entry.path)
55 continue
56 if entry.is_file() and '.' in entry.name:
57 if entry.name not in textures.keys():
58 textures[entry.name] = entry.path
59 for path2 in dirs:
60 collect_files(path2)
61
62 def average_color(filename):
63 inp = Image.open(filename).convert('RGBA')
64 data = inp.load()
65
66 c0, c1, c2 = [], [], []
67 for x in range(inp.size[0]):
68 for y in range(inp.size[1]):
69 px = data[x, y]
70 if px[3] < 128: continue # alpha
71 c0.append(px[0]**2)
72 c1.append(px[1]**2)
73 c2.append(px[2]**2)
74
75 if len(c0) == 0:
76 print(f"didn't find color for '{os.path.basename(filename)}'", file=sys.stderr)
77 return "0 0 0"
78 c0 = sqrt(sum(c0) / len(c0))
79 c1 = sqrt(sum(c1) / len(c1))
80 c2 = sqrt(sum(c2) / len(c2))
81 return "%d %d %d" % (c0, c1, c2)
82
83 def apply_sed(line, exprs):
84 for expr in exprs:
85 if expr[0] == '/':
86 if not expr.endswith("/d"): raise ValueError()
87 if re.search(expr[1:-2], line):
88 return ''
89 elif expr[0] == 's':
90 expr = expr.split(expr[1])
91 if len(expr) != 4 or expr[3] != '': raise ValueError()
92 line = re.sub(expr[1], expr[2], line)
93 else:
94 raise ValueError()
95 return line
96 #
97
98 try:
99 opts, args = getopt.getopt(sys.argv[1:], "hg:m:", ["help", "game=", "mods=", "replace="])
100 except getopt.GetoptError as e:
101 print(str(e))
102 exit(1)
103 if ('-h', '') in opts or ('--help', '') in opts:
104 usage()
105 exit(0)
106
107 input_file = "./nodes.txt"
108 output_file = "./colors.txt"
109 texturepaths = []
110
111 try:
112 gamepath = next(o[1] for o in opts if o[0] in ('-g', '--game'))
113 if not os.path.isdir(os.path.join(gamepath, "mods")):
114 print(f"'{gamepath}' doesn't exist or does not contain a game.", file=sys.stderr)
115 exit(1)
116 texturepaths.append(os.path.join(gamepath, "mods"))
117 except StopIteration:
118 print("No game path set but one is required. (see --help)", file=sys.stderr)
119 exit(1)
120
121 try:
122 tmp = next(o[1] for o in opts if o[0] == "--replace")
123 REPLACEMENTS.clear()
124 with open(tmp, 'r') as f:
125 for line in f:
126 if not line or line[0] == '#': continue
127 REPLACEMENTS.append(line.strip())
128 except StopIteration:
129 pass
130
131 for o in opts:
132 if o[0] not in ('-m', '--mods'): continue
133 if not os.path.isdir(o[1]):
134 print(f"Given path '{o[1]}' does not exist.'", file=sys.stderr)
135 exit(1)
136 texturepaths.append(o[1])
137
138 if len(args) > 2:
139 print("Too many arguments.", file=sys.stderr)
140 exit(1)
141 if len(args) > 1:
142 output_file = args[1]
143 if len(args) > 0:
144 input_file = args[0]
145
146 if not os.path.exists(input_file) or os.path.isdir(input_file):
147 print(f"Input file '{input_file}' does not exist.", file=sys.stderr)
148 exit(1)
149
150 #
151
152 print(f"Collecting textures from {len(texturepaths)} path(s)... ", end="", flush=True)
153 textures = {}
154 for path in texturepaths:
155 collect_files(path)
156 print("done")
157
158 print("Processing nodes...")
159 fin = open(input_file, 'r')
160 fout = open(output_file, 'w')
161 n = 0
162 for line in fin:
163 line = line.rstrip('\r\n')
164 if not line or line[0] == '#':
165 fout.write(line + '\n')
166 continue
167 node, tex = line.split(" ")
168 if not tex or tex == "blank.png":
169 continue
170 elif tex not in textures.keys():
171 print(f"skip {node} texture not found")
172 continue
173 color = average_color(textures[tex])
174 line = f"{node} {color}"
175 #print(f"ok {node}")
176 line = apply_sed(line, REPLACEMENTS)
177 if line:
178 fout.write(line + '\n')
179 n += 1
180 fin.close()
181 fout.close()
182 print(f"Done, {n} entries written.")
4242 oss << "Setting '" << name << "' not found";
4343 throw std::runtime_error(oss.str());
4444 }
45
46 std::string read_setting_default(const std::string &name, std::istream &is,
47 const std::string &def)
48 {
49 try {
50 return read_setting(name, is);
51 } catch(const std::runtime_error &e) {
52 return def;
53 }
54 }