11 Commits

Author SHA1 Message Date
1c16c40ccc Apply Luanti rename 2024-11-11 09:53:35 +01:00
dd5c4e509d Fix docker workflow 2024-10-04 12:15:49 +02:00
0982a03dbd Add Dockerfile and workflow to publish image (#102) 2024-08-11 19:26:15 +02:00
dd1904a667 Run CI test also with ASan 2024-04-20 21:38:15 +02:00
40a5e16e21 Save a copy during zlib decompression 2024-04-20 21:38:05 +02:00
7e4caacb9e Upgrade CI workflow packages and Ubuntu version (#101) 2024-02-17 20:54:03 +01:00
e14f27f412 Add cautionary note about sat_mul() 2023-08-08 14:18:58 +02:00
7af222dd9d Fix dumpnodes crash on deprecated tile field name 2023-04-08 16:32:29 +02:00
c81cda24d3 Fix bad slicing interval for negative --min-y / --max-y values 2023-01-29 16:22:41 +01:00
8a7333ef49 Fix package install in CI
shoutout to github for shipping broken OS images
2023-01-29 14:44:03 +01:00
7fb3b9edd6 Fix Postgres linking on older CMake
(see 998e4820c9)
2022-06-19 14:14:09 +02:00
15 changed files with 199 additions and 48 deletions

16
.dockerignore Normal file
View File

@ -0,0 +1,16 @@
.git
.github
*~
minetestmapper
minetestmapper.exe
CMakeCache.txt
CMakeFiles/
CPack*.cmake
_CPack_Packages/
install_manifest.txt
Makefile
cmake_install.cmake
cmake_config.h

View File

@ -7,19 +7,21 @@ on:
- '**.[ch]'
- '**.cpp'
- '**/CMakeLists.txt'
- 'util/ci/**'
- '.github/workflows/**.yml'
pull_request:
paths:
- '**.[ch]'
- '**.cpp'
- '**/CMakeLists.txt'
- 'util/ci/**'
- '.github/workflows/**.yml'
jobs:
gcc:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install deps
run: |
source util/ci/script.sh
@ -39,9 +41,9 @@ jobs:
do_functional_test
clang:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install deps
run: |
source util/ci/script.sh

87
.github/workflows/docker_image.yml vendored Normal file
View File

@ -0,0 +1,87 @@
---
name: docker_image
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images
# https://docs.docker.com/build/ci/github-actions/multi-platform
# https://github.com/opencontainers/image-spec/blob/main/annotations.md
on:
push:
branches: [ "master" ]
# Publish semver tags as releases.
tags: [ "*" ]
pull_request:
# Build docker image on pull requests. (but do not publish)
paths:
- '**/**.[ch]'
- '**/**.cpp'
workflow_dispatch:
inputs:
use_cache:
description: "Use build cache"
required: true
type: boolean
default: true
env:
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3.0.0
# Login against the Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5.5.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.title=Minetestmapper
org.opencontainers.image.vendor=Luanti
org.opencontainers.image.licenses=BSD 2-Clause
# Build and push Docker image
# https://github.com/docker/build-push-action
# No arm support for now. Require cross-compilation support in Dockerfile to not use QEMU.
- name: Build and push Docker image
uses: docker/build-push-action@v5.1.0
with:
context: .
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
load: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
no-cache: ${{ (github.event_name == 'workflow_dispatch' && !inputs.use_cache) || startsWith(github.ref, 'refs/tags/') }}
- name: Test Docker Image
run: |
docker run --rm $(cut -d, -f1 <<<"$DOCKER_METADATA_OUTPUT_TAGS") minetestmapper --help
shell: bash

View File

@ -19,7 +19,7 @@ if(WIN32)
set(BINDIR ".")
set(DOCDIR ".")
else()
set(SHAREDIR "share/minetest") # reuse Minetest share dir
set(SHAREDIR "share/luanti") # reuse engine share dir
set(BINDIR "bin")
set(DOCDIR "share/doc/${PROJECT_NAME}")
set(MANDIR "share/man")
@ -86,6 +86,7 @@ if(ENABLE_POSTGRESQL)
if(PostgreSQL_INCLUDE_DIR AND PostgreSQL_LIBRARY)
set(PostgreSQL_FOUND TRUE)
set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR})
set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY})
endif()
else()
find_package(PostgreSQL)
@ -208,7 +209,7 @@ if(UNIX)
install(FILES "minetestmapper.6" DESTINATION "${MANDIR}/man6")
endif()
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Overview mapper for Minetest")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Overview mapper for Luanti")
set(CPACK_PACKAGE_VENDOR "celeron55")
set(CPACK_PACKAGE_CONTACT "Perttu Ahola <celeron55@gmail.com>")

24
Dockerfile Normal file
View File

@ -0,0 +1,24 @@
ARG DOCKER_IMAGE=alpine:3.20
FROM $DOCKER_IMAGE AS builder
RUN apk add --no-cache build-base cmake \
gd-dev sqlite-dev postgresql-dev hiredis-dev leveldb-dev \
ninja
COPY . /usr/src/minetestmapper
WORKDIR /usr/src/minetestmapper
RUN cmake -B build -G Ninja && \
cmake --build build --parallel $(nproc) && \
cmake --install build
FROM $DOCKER_IMAGE AS runtime
RUN apk add --no-cache libstdc++ libgcc libpq \
gd sqlite-libs postgresql hiredis leveldb
COPY --from=builder /usr/local/share/luanti /usr/local/share/luanti
COPY --from=builder /usr/local/bin/minetestmapper /usr/local/bin/minetestmapper
COPY COPYING /usr/local/share/minetest/minetestmapper.COPYING
ENTRYPOINT ["/usr/local/bin/minetestmapper"]

View File

@ -4,10 +4,11 @@ Minetest Mapper C++
.. image:: https://github.com/minetest/minetestmapper/workflows/build/badge.svg
:target: https://github.com/minetest/minetestmapper/actions/workflows/build.yml
Minetestmapper generates an overview image from a Minetest map.
Minetestmapper generates an overview image from a Luanti map.
A port of minetestmapper.py to C++ from https://github.com/minetest/minetest/tree/0.4.17/util.
This version is both faster and provides more features than the now obsolete Python script.
A port of minetestmapper.py to C++ from `the obsolete Python script
<https://github.com/minetest/minetest/tree/0.4.17/util>`_.
This version is both faster and provides more features.
Minetestmapper ships with a colors.txt file for Minetest Game, if you use a different game or have
many mods installed you should generate a matching colors.txt for better results.
@ -39,7 +40,7 @@ for Windows:
Minetestmapper for Windows can be downloaded `from the Releases section
<https://github.com/minetest/minetestmapper/releases>`_.
After extracting the archive, it can be invoked from cmd.exe:
After extracting the archive, it can be invoked from cmd.exe or PowerShell:
::
cd C:\Users\yourname\Desktop\example\path
@ -116,7 +117,7 @@ zoom:
Apply zoom to drawn nodes by enlarging them to n*n squares, e.g. ``--zoom 4``
colors:
Override auto-detected path to colors.txt, e.g. ``--colors ../minetest/mycolors.txt``
Override auto-detected path to colors.txt, e.g. ``--colors ../world/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

@ -43,6 +43,8 @@ inline T sat_mul(T a, T b)
return std::numeric_limits<T>::max();
return res;
#else
// WARNING: the fallback implementation is incorrect since we compute ceil(log(x)) not log(x)
// but that's good enough for our usecase...
const int bits = sizeof(T) * 8;
int hb_a = 0, hb_b = 0;
for (int i = bits - 1; i >= 0; i--) {
@ -426,19 +428,27 @@ void TileGenerator::closeDatabase()
m_db = NULL;
}
static inline int16_t mod16(int16_t y)
{
if (y < 0)
return (y - 15) / 16;
return y / 16;
}
void TileGenerator::loadBlocks()
{
const int16_t yMax = m_yMax / 16 + 1;
const int16_t yMax = mod16(m_yMax) + 1;
const int16_t yMin = mod16(m_yMin);
if (m_exhaustiveSearch == EXH_NEVER || m_exhaustiveSearch == EXH_Y) {
std::vector<BlockPos> vec = m_db->getBlockPos(
BlockPos(m_geomX, m_yMin / 16, m_geomY),
BlockPos(m_geomX, yMin, m_geomY),
BlockPos(m_geomX2, yMax, m_geomY2)
);
for (auto pos : vec) {
assert(pos.x >= m_geomX && pos.x < m_geomX2);
assert(pos.y >= m_yMin / 16 && pos.y < yMax);
assert(pos.y >= yMin && pos.y < yMax);
assert(pos.z >= m_geomY && pos.z < m_geomY2);
// Adjust minimum and maximum positions to the nearest block
@ -512,7 +522,8 @@ void TileGenerator::createImage()
void TileGenerator::renderMap()
{
BlockDecoder blk;
const int16_t yMax = m_yMax / 16 + 1;
const int16_t yMax = mod16(m_yMax) + 1;
const int16_t yMin = mod16(m_yMin);
size_t count = 0;
auto renderSingle = [&] (int16_t xPos, int16_t zPos, BlockList &blockStack) {
@ -529,7 +540,7 @@ void TileGenerator::renderMap()
for (const auto &it : blockStack) {
const BlockPos pos = it.first;
assert(pos.x == xPos && pos.z == zPos);
assert(pos.y >= m_yMin / 16 && pos.y < yMax);
assert(pos.y >= yMin && pos.y < yMax);
blk.reset();
blk.decode(it.second);
@ -557,7 +568,7 @@ void TileGenerator::renderMap()
int16_t xPos = *it2;
BlockList blockStack;
m_db->getBlocksOnXZ(blockStack, xPos, zPos, m_yMin / 16, yMax);
m_db->getBlocksOnXZ(blockStack, xPos, zPos, yMin, yMax);
blockStack.sort();
renderSingle(xPos, zPos, blockStack);
@ -568,17 +579,17 @@ void TileGenerator::renderMap()
} else if (m_exhaustiveSearch == EXH_Y) {
#ifndef NDEBUG
std::cerr << "Exhaustively searching height of "
<< (yMax - (m_yMin / 16)) << " blocks" << std::endl;
<< (yMax - yMin) << " blocks" << std::endl;
#endif
std::vector<BlockPos> positions;
positions.reserve(yMax - (m_yMin / 16));
positions.reserve(yMax - yMin);
for (auto it = m_positions.rbegin(); it != m_positions.rend(); ++it) {
int16_t zPos = it->first;
for (auto it2 = it->second.rbegin(); it2 != it->second.rend(); ++it2) {
int16_t xPos = *it2;
positions.clear();
for (int16_t yPos = m_yMin / 16; yPos < yMax; yPos++)
for (int16_t yPos = yMin; yPos < yMax; yPos++)
positions.emplace_back(xPos, yPos, zPos);
BlockList blockStack;
@ -591,7 +602,7 @@ void TileGenerator::renderMap()
postRenderRow(zPos);
}
} else if (m_exhaustiveSearch == EXH_FULL) {
const size_t span_y = yMax - (m_yMin / 16);
const size_t span_y = yMax - yMin;
m_progressMax = (m_geomX2 - m_geomX) * span_y * (m_geomY2 - m_geomY);
#ifndef NDEBUG
std::cerr << "Exhaustively searching "
@ -604,7 +615,7 @@ void TileGenerator::renderMap()
for (int16_t zPos = m_geomY2 - 1; zPos >= m_geomY; zPos--) {
for (int16_t xPos = m_geomX2 - 1; xPos >= m_geomX; xPos--) {
positions.clear();
for (int16_t yPos = m_yMin / 16; yPos < yMax; yPos++)
for (int16_t yPos = yMin; yPos < yMax; yPos++)
positions.emplace_back(xPos, yPos, zPos);
BlockList blockStack;

View File

@ -29,31 +29,39 @@ ustring ZlibDecompressor::decompress()
const size_t size = m_size - m_seekPos;
ustring buffer;
constexpr size_t BUFSIZE = 128 * 1024;
unsigned char temp_buffer[BUFSIZE];
constexpr size_t BUFSIZE = 32 * 1024;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = Z_NULL;
strm.avail_in = size;
strm.avail_in = 0;
if (inflateInit(&strm) != Z_OK)
throw DecompressError();
strm.next_in = const_cast<unsigned char *>(data);
strm.avail_in = size;
buffer.resize(BUFSIZE);
strm.next_out = &buffer[0];
strm.avail_out = BUFSIZE;
int ret = 0;
do {
strm.avail_out = BUFSIZE;
strm.next_out = temp_buffer;
ret = inflate(&strm, Z_NO_FLUSH);
buffer.append(temp_buffer, BUFSIZE - strm.avail_out);
if (strm.avail_out == 0) {
const auto off = buffer.size();
buffer.reserve(off + BUFSIZE);
strm.next_out = &buffer[off];
strm.avail_out = BUFSIZE;
}
} while (ret == Z_OK);
if (ret != Z_STREAM_END)
throw DecompressError();
m_seekPos += strm.next_in - data;
buffer.resize(buffer.size() - strm.avail_out);
(void) inflateEnd(&strm);
return buffer;

View File

@ -7,9 +7,5 @@
#ifdef USE_CMAKE_CONFIG_H
#include "cmake_config.h"
#else
#define USE_POSTGRESQL 0
#define USE_LEVELDB 0
#define USE_REDIS 0
#define SHAREDIR "/usr/share/minetest"
#error missing config
#endif

View File

@ -39,7 +39,7 @@ static void usage()
};
const char *top_text =
"minetestmapper -i <world_path> -o <output_image.png> [options]\n"
"Generate an overview image of a Minetest map.\n"
"Generate an overview image of a Luanti map.\n"
"\n"
"Options:\n";
const char *bottom_text =

View File

@ -1,6 +1,6 @@
.TH MINETESTMAPPER 6
.SH NAME
minetestmapper \- generate an overview image of a Minetest map
minetestmapper \- generate an overview image of a Luanti map
.SH SYNOPSIS
.B minetestmapper
\fB\-i\fR \fIworld_path\fR
@ -9,9 +9,9 @@ minetestmapper \- generate an overview image of a Minetest map
See additional optional parameters below.
.SH DESCRIPTION
.B minetestmapper
generates an overview image of a minetest map. This is a port of
generates an overview image of a Luanti 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.
provides more functionality than the obsolete Python script.
.SH MANDATORY PARAMETERS
.TP
.BR \-i " " \fIworld_path\fR
@ -86,7 +86,7 @@ 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"
Forcefully set path to colors.txt file (autodetected otherwise), e.g. "--colors ../world/mycolors.txt"
.TP
.BR \-\-scales " " \fIedges\fR

View File

@ -7,7 +7,7 @@ variant=win32
[[ "$(basename "$CXX")" == "x86_64-"* ]] && variant=win64
#######
# this expects unpacked libraries similar to what Minetest's buildbot uses
# this expects unpacked libraries similar to what Luanti's buildbot uses
# $extradlls will typically point to the DLLs for libgcc, libstdc++ and libpng
libgd_dir=
zlib_dir=

View File

@ -4,12 +4,17 @@ install_linux_deps() {
local pkgs=(cmake libgd-dev libsqlite3-dev libleveldb-dev libpq-dev libhiredis-dev libzstd-dev)
sudo apt-get update
sudo apt-get install -y --no-install-recommends ${pkgs[@]} "$@"
sudo apt-get remove -y 'libgd3' nginx || : # ????
sudo apt-get install -y --no-install-recommends "${pkgs[@]}" "$@"
}
run_build() {
cmake . -DCMAKE_BUILD_TYPE=Debug \
local args=(
-DCMAKE_BUILD_TYPE=Debug
-DENABLE_LEVELDB=1 -DENABLE_POSTGRESQL=1 -DENABLE_REDIS=1
)
[[ "$CXX" == clang* ]] && args+=(-DCMAKE_CXX_FLAGS="-fsanitize=address")
cmake . "${args[@]}"
make -j2
}

View File

@ -1,7 +1,7 @@
local function get_tile(tiles, n)
local tile = tiles[n]
if type(tile) == 'table' then
return tile.name
return tile.name or tile.image
end
return tile
end
@ -15,7 +15,7 @@ local function pairs_s(dict)
return ipairs(keys)
end
minetest.register_chatcommand("dumpnodes", {
core.register_chatcommand("dumpnodes", {
description = "Dump node and texture list for use with minetestmapper",
func = function()
local ntbl = {}
@ -30,7 +30,7 @@ minetest.register_chatcommand("dumpnodes", {
ntbl[prefix][name] = true
end
end
local out, err = io.open(minetest.get_worldpath() .. "/nodes.txt", 'wb')
local out, err = io.open(core.get_worldpath() .. "/nodes.txt", 'wb')
if not out then
return true, err
end
@ -39,7 +39,7 @@ minetest.register_chatcommand("dumpnodes", {
out:write('# ' .. prefix .. '\n')
for _, name in pairs_s(ntbl[prefix]) do
local nn = prefix .. ":" .. name
local nd = minetest.registered_nodes[nn]
local nd = core.registered_nodes[nn]
local tiles = nd.tiles or nd.tile_images
if tiles == nil or nd.drawtype == 'airlike' then
print("ignored(2): " .. nn)

View File

@ -13,14 +13,14 @@ except:
############
############
# Instructions for generating a colors.txt file for custom games and/or mods:
# 1) Add the dumpnodes mod to a Minetest world with the chosen game and mods enabled.
# 1) Add the dumpnodes mod to a Luanti world with the chosen game and mods enabled.
# 2) Join ingame and run the /dumpnodes chat command.
# 3) Run this script and poin it to the installation path of the game using -g,
# the path(s) where mods are stored using -m and the nodes.txt in your world folder.
# Example command line:
# ./util/generate_colorstxt.py --game /usr/share/minetest/games/minetest_game \
# ./util/generate_colorstxt.py --game /usr/share/luanti/games/minetest_game \
# -m ~/.minetest/mods ~/.minetest/worlds/my_world/nodes.txt
# 4) Copy the resulting colors.txt file to your world folder or to any other places
# 4) Copy the resulting colors.txt file to your world folder or to any other place
# and use it with minetestmapper's --colors option.
###########
###########