Browse Source

display backend and mapper_path being used

and improve PEP8 compliance of minetestmapper fork (already submitted
pull request from github.com/expertmm/minetest)
master
poikilos 8 years ago
committed by Jacob Gustafson
parent
commit
269852a4f0
  1. 197
      minetestmapper-expertmm.py
  2. 2
      singleimage.py

197
minetestmapper-expertmm.py

@ -1,13 +1,7 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the WTFPL
# Public License, Version 2, as published by Sam Hocevar. See
# COPYING for more details.
# Made by Jogge, modified by celeron55
# Made by Jogge, modified by: celeron55, expertmm
# 2011-05-29: j0gge: initial release
# 2011-05-30: celeron55: simultaneous support for sectors/sectors2, removed
# 2011-06-02: j0gge: command line parameters, coordinates, players, ...
@ -16,12 +10,15 @@
# 2011-07-30: WF: Support for content types extension, refactoring
# 2011-07-30: erlehmann: PEP 8 compliance.
# 2016-03-08: expertmm: geometry and region params
# 2017-03-17: expertmm: removed license from this file (this file should fall
# under the license of minetest)
# 2017-04-12: expertmm: PEP8 compliance
# Requires Python Imaging Library: http://www.pythonware.com/products/pil/
# Some speed-up: ...lol, actually it slows it down.
#import psyco ; psyco.full()
#from psyco.classes import *
# import psyco ; psyco.full()
# from psyco.classes import *
import zlib
import os
@ -89,19 +86,22 @@ def int_to_hex4(i):
def getBlockAsInteger(p):
return p[2]*16777216 + p[1]*4096 + p[0]
def unsignedToSigned(i, max_positive):
if i < max_positive:
return i
else:
return i - 2*max_positive
def getIntegerAsBlock(i):
x = unsignedToSigned(i % 4096, 2048)
i = int((i - x) / 4096)
y = unsignedToSigned(i % 4096, 2048)
i = int((i - y) / 4096)
z = unsignedToSigned(i % 4096, 2048)
return x,y,z
return x, y, z
def limit(i, l, h):
if(i > h):
@ -110,17 +110,24 @@ def limit(i, l, h):
i = l
return i
def readU8(f):
return ord(f.read(1))
def readU16(f):
return ord(f.read(1))*256 + ord(f.read(1))
def readU32(f):
return ord(f.read(1))*256*256*256 + ord(f.read(1))*256*256 + ord(f.read(1))*256 + ord(f.read(1))
return ord(f.read(1))*256*256*256 + ord(f.read(1))*256*256 + \
ord(f.read(1))*256 + ord(f.read(1))
def readS32(f):
return unsignedToSigned(ord(f.read(1))*256*256*256 + ord(f.read(1))*256*256 + ord(f.read(1))*256 + ord(f.read(1)), 2**31)
return unsignedToSigned(ord(f.read(1))*256*256*256 +
ord(f.read(1))*256*256 + ord(f.read(1))*256 +
ord(f.read(1)), 2**31)
usagetext = """minetestmapper.py [options]
-i/--input <world_path>
@ -226,24 +233,24 @@ if geometry_string is not None:
nonchunky_xmax = nonchunky_xmin + this_width - 1 # inclusive rect
nonchunky_zmin = z
nonchunky_zmax = nonchunky_zmin + this_height - 1 # inclusive rect
print("#geometry:")
print("# x:" + str(x))
print("# z:" + str(z))
print("# width:" + str(this_width))
print("# height:" + str(this_height))
print("region:")
print(" xmin:" + str(nonchunky_xmin))
print(" xmax:" + str(nonchunky_xmax))
print(" zmin:" + str(nonchunky_zmin))
print(" zmax:" + str(nonchunky_zmax))
print("#geometry:" + "\n" +
"# x:" + str(x) + "\n" +
"# z:" + str(z) + "\n" +
"# width:" + str(this_width) + "\n" +
"# height:" + str(this_height) + "\n" +
"region:" + "\n" +
" xmin:" + str(nonchunky_xmin) + "\n" +
" xmax:" + str(nonchunky_xmax) + "\n" +
" zmin:" + str(nonchunky_zmin) + "\n" +
" zmax:" + str(nonchunky_zmax))
else:
print("ERROR: Missing coordinates in '" + geometry_string +
"' for geometry (must be in the form: x:z+width+height)")
usage()
sys.exit(2)
else:
print("ERROR: Incorrect value '" + geometry_string +
"' for geometry (must be in the form: x:z+width+height)")
print("ERROR: Incorrect geometry syntax '" + geometry_string +
"' (must be in the form: x:z+width+height)")
usage()
sys.exit(2)
elif region_string is not None:
@ -258,11 +265,11 @@ elif region_string is not None:
nonchunky_xmax = int(xmax_string)
nonchunky_zmin = int(zmin_string)
nonchunky_zmax = int(zmax_string)
print("region:")
print(" xmin:" + str(nonchunky_xmin))
print(" xmax:" + str(nonchunky_xmax))
print(" zmin:" + str(nonchunky_zmin))
print(" zmax:" + str(nonchunky_zmax))
print("region:" + "\n" +
" xmin:" + str(nonchunky_xmin) + "\n" +
" xmax:" + str(nonchunky_xmax) + "\n" +
" zmin:" + str(nonchunky_zmin) + "\n" +
" zmax:" + str(nonchunky_zmax))
else:
print("ERROR: Incorrect value '" + region_string +
"' for region (must be in the form: xmin:xmax,zmin:zmax)")
@ -341,8 +348,8 @@ for line in f:
int(values[3]))
f.close()
#print("colors: "+repr(colors))
#sys.exit(1)
# print("colors: "+repr(colors))
# sys.exit(1)
xlist = []
zlist = []
@ -411,8 +418,8 @@ maxz = max(zlist)
w = (maxx - minx) * 16 + 16
h = (maxz - minz) * 16 + 16
print("Result image (w=" + str(w) + " h=" + str(h) + ") will be written to "
+ output)
print("Result image (w=" + str(w) + " h=" + str(h) + ") will be written to " +
output)
im = Image.new("RGB", (w + border, h + border), bgcolor)
draw = ImageDraw.Draw(im)
@ -427,15 +434,19 @@ starttime = time.time()
CONTENT_WATER = 2
def content_is_ignore(d):
return d in [0, "ignore"]
def content_is_water(d):
return d in [2, 9]
def content_is_air(d):
return d in [126, 127, 254, "air"]
def read_content(mapdata, version, datapos):
if version >= 24:
return (mapdata[datapos*2] << 8) | (mapdata[datapos*2 + 1])
@ -450,14 +461,15 @@ def read_content(mapdata, version, datapos):
raise Exception("Unsupported map format: " + str(version))
def read_mapdata(mapdata, version, pixellist, water, day_night_differs, id_to_name):
def read_mapdata(mapdata, version, pixellist, water, day_night_differs,
id_to_name):
global stuff # oh my :-)
global unknown_node_names
global unknown_node_ids
if(len(mapdata) < 4096):
print("bad: " + xhex + "/" + zhex + "/" + yhex + " " + \
str(len(mapdata)))
print("bad: " + xhex + "/" + zhex + "/" + yhex + " " +
str(len(mapdata)))
else:
chunkxpos = xpos * 16
chunkypos = ypos * 16
@ -481,31 +493,37 @@ def read_mapdata(mapdata, version, pixellist, water, day_night_differs, id_to_na
elif content_is_water(content):
water[(x, z)] += 1
# Add dummy stuff for drawing sea without seabed
stuff[(chunkxpos + x, chunkzpos + z)] = (
chunkypos + y, content, water[(x, z)], day_night_differs)
stuff[(chunkxpos + x, chunkzpos + z)] = (chunkypos + y,
content,
water[(x, z)],
day_night_differs)
elif content in colors:
# Memorize information on the type and height of
# the block and for drawing the picture.
stuff[(chunkxpos + x, chunkzpos + z)] = (
chunkypos + y, content, water[(x, z)], day_night_differs)
stuff[(chunkxpos + x, chunkzpos + z)] = (chunkypos + y,
content,
water[(x, z)],
day_night_differs)
pixellist.remove((x, z))
break
else:
if type(content) == str:
if content not in unknown_node_names:
unknown_node_names.append(content)
#print("unknown node: %s/%s/%s x: %d y: %d z: %d block name: %s"
# % (xhex, zhex, yhex, x, y, z, content))
# print("unknown node: %s/%s/%s x: %d y: %d z: %d" +
# " block name: %s"
# % (xhex, zhex, yhex, x, y, z, content))
else:
if content not in unknown_node_ids:
unknown_node_ids.append(content)
#print("unknown node: %s/%s/%s x: %d y: %d z: %d block id: %x"
# % (xhex, zhex, yhex, x, y, z, content))
# print("unknown node: %s/%s/%s x: %d y: %d z: %d" +
# " block id: %x"
# % (xhex, zhex, yhex, x, y, z, content))
# Go through all sectors.
for n in range(len(xlist)):
#if n > 500:
# if n > 500:
# break
if n % 200 == 0:
nowtime = time.time()
@ -520,10 +538,10 @@ for n in range(len(xlist)):
remaining_s = time_guess - dtime
remaining_minutes = int(remaining_s / 60)
remaining_s -= remaining_minutes * 60
print("Processing sector " + str(n) + " of " + str(len(xlist))
+ " (" + str(round(100.0 * n / len(xlist), 1)) + "%)"
+ " (ETA: " + str(remaining_minutes) + "m "
+ str(int(remaining_s)) + "s)")
print("Processing sector " + str(n) + " of " + str(len(xlist)) +
" (" + str(round(100.0 * n / len(xlist), 1)) + "%)" +
" (ETA: " + str(remaining_minutes) + "m " +
str(int(remaining_s)) + "s)")
xpos = xlist[n]
zpos = zlist[n]
@ -543,7 +561,9 @@ for n in range(len(xlist)):
if cur:
psmin = getBlockAsInteger((xpos, -2048, zpos))
psmax = getBlockAsInteger((xpos, 2047, zpos))
cur.execute("SELECT `pos` FROM `blocks` WHERE `pos`>=? AND `pos`<=? AND (`pos` - ?) % 4096 = 0", (psmin, psmax, psmin))
cur.execute("SELECT `pos` FROM `blocks` WHERE `pos`>=?"
" AND `pos`<=? AND (`pos` - ?) % 4096 = 0",
(psmin, psmax, psmin))
while True:
r = cur.fetchone()
if not r:
@ -590,13 +610,14 @@ for n in range(len(xlist)):
# Go through the Y axis from top to bottom.
for ypos in reversed(ylist):
try:
#print("("+str(xpos)+","+str(ypos)+","+str(zpos)+")")
# print("("+str(xpos)+","+str(ypos)+","+str(zpos)+")")
yhex = int_to_hex4(ypos)
if sectortype == "sqlite":
ps = getBlockAsInteger((xpos, ypos, zpos))
cur.execute("SELECT `data` FROM `blocks` WHERE `pos`==? LIMIT 1", (ps,))
cur.execute("SELECT `data` FROM `blocks`"
" WHERE `pos`==? LIMIT 1", (ps,))
r = cur.fetchone()
if not r:
continue
@ -605,15 +626,16 @@ for n in range(len(xlist)):
if sectortype == "old":
filename = path + "sectors/" + sector1 + "/" + yhex.lower()
else:
filename = path + "sectors2/" + sector2 + "/" + yhex.lower()
filename = path + "sectors2/" + sector2 + "/" + \
yhex.lower()
f = file(filename, "rb")
# Let's just memorize these even though it's not really necessary.
version = readU8(f)
flags = f.read(1)
#print("version="+str(version))
#print("flags="+str(version))
# print("version="+str(version))
# print("flags="+str(version))
# Check flags
is_underground = ((ord(flags) & 1) != 0)
@ -621,10 +643,10 @@ for n in range(len(xlist)):
lighting_expired = ((ord(flags) & 4) != 0)
generated = ((ord(flags) & 8) != 0)
#print("is_underground="+str(is_underground))
#print("day_night_differs="+str(day_night_differs))
#print("lighting_expired="+str(lighting_expired))
#print("generated="+str(generated))
# print("is_underground="+str(is_underground))
# print("day_night_differs="+str(day_night_differs))
# print("lighting_expired="+str(lighting_expired))
# print("generated="+str(generated))
if version >= 22:
content_width = readU8(f)
@ -638,9 +660,9 @@ for n in range(len(xlist)):
mapdata = []
# Reuse the unused tail of the file
f.close();
f.close()
f = cStringIO.StringIO(dec_o.unused_data)
#print("unused data: "+repr(dec_o.unused_data))
# print("unused data: "+repr(dec_o.unused_data))
# zlib-compressed node metadata list
dec_o = zlib.decompressobj()
@ -651,9 +673,9 @@ for n in range(len(xlist)):
metaliststr = []
# Reuse the unused tail of the file
f.close();
f.close()
f = cStringIO.StringIO(dec_o.unused_data)
#print("* dec_o.unused_data: "+repr(dec_o.unused_data))
# print("* dec_o.unused_data: "+repr(dec_o.unused_data))
data_after_node_metadata = dec_o.unused_data
if version <= 21:
@ -661,12 +683,12 @@ for n in range(len(xlist)):
readU16(f)
if version == 23:
readU8(f) # Unused node timer version (always 0)
readU8(f) # Unused node timer version (always 0)
if version == 24:
ver = readU8(f)
if ver == 1:
num = readU16(f)
for i in range(0,num):
for i in range(0, num):
readU16(f)
readS32(f)
readS32(f)
@ -688,44 +710,46 @@ for n in range(len(xlist)):
data = f.read(data_size)
timestamp = readU32(f)
#print("* timestamp="+str(timestamp))
# print("* timestamp="+str(timestamp))
id_to_name = {}
if version >= 22:
name_id_mapping_version = readU8(f)
num_name_id_mappings = readU16(f)
#print("* num_name_id_mappings: "+str(num_name_id_mappings))
# print("* num_name_id_mappings: "+str(num_name_id_mappings))
for i in range(0, num_name_id_mappings):
node_id = readU16(f)
name_len = readU16(f)
name = f.read(name_len)
#print(str(node_id)+" = "+name)
# print(str(node_id)+" = "+name)
id_to_name[node_id] = name
# Node timers
if version >= 25:
timer_size = readU8(f)
num = readU16(f)
for i in range(0,num):
for i in range(0, num):
readU16(f)
readS32(f)
readS32(f)
read_mapdata(mapdata, version, pixellist, water, day_night_differs, id_to_name)
read_mapdata(mapdata, version, pixellist, water, day_night_differs,
id_to_name)
# After finding all the pixels in the sector, we can move on to
# the next sector without having to continue the Y axis.
if(len(pixellist) == 0):
break
except Exception as e:
print("Error at ("+str(xpos)+","+str(ypos)+","+str(zpos)+"): "+str(e))
print("Error at (" + str(xpos) + "," + str(ypos) + "," +
str(zpos) + "): " + str(e))
sys.stdout.write("Block data: ")
for c in r[0]:
sys.stdout.write("%2.2x "%ord(c))
sys.stdout.write("%2.2x " % ord(c))
sys.stdout.write(os.linesep)
sys.stdout.write("Data after node metadata: ")
for c in data_after_node_metadata:
sys.stdout.write("%2.2x "%ord(c))
sys.stdout.write("%2.2x " % ord(c))
sys.stdout.write(os.linesep)
traceback.print_exc()
@ -748,10 +772,10 @@ for (x, z) in stuff.iterkeys():
remaining_s = time_guess - dtime
remaining_minutes = int(remaining_s / 60)
remaining_s -= remaining_minutes * 60
print("Drawing pixel " + str(n) + " of " + str(listlen)
+ " (" + str(round(100.0 * n / listlen, 1)) + "%)"
+ " (ETA: " + str(remaining_minutes) + "m "
+ str(int(remaining_s)) + "s)")
print("Drawing pixel " + str(n) + " of " + str(listlen) +
" (" + str(round(100.0 * n / listlen, 1)) + "%)" +
" (ETA: " + str(remaining_minutes) + "m " +
str(int(remaining_s)) + "s)")
n += 1
(r, g, b) = colors[stuff[(x, z)][1]]
@ -774,7 +798,7 @@ for (x, z) in stuff.iterkeys():
if not dnd:
d = -69
elif not content_is_water(c1) and not content_is_water(c2) and \
not content_is_water(c):
not content_is_water(c):
y = stuff[(x, z)][0]
y1 = stuff[(x - 1, z)][0] if dnd1 else y
y2 = stuff[(x, z + 1)][0] if dnd2 else y
@ -802,8 +826,8 @@ for (x, z) in stuff.iterkeys():
if draworigin:
draw.ellipse((minx * -16 - 5 + border, h - minz * -16 - 6 + border,
minx * -16 + 5 + border, h - minz * -16 + 4 + border),
outline=origincolor)
minx * -16 + 5 + border, h - minz * -16 + 4 + border),
outline=origincolor)
font = ImageFont.load_default()
@ -813,15 +837,15 @@ if drawscale:
for n in range(int(minx / -4) * -4, maxx, 4):
draw.text((minx * -16 + n * 16 + 2 + border, 0), str(n * 16),
font=font, fill=scalecolor)
font=font, fill=scalecolor)
draw.line((minx * -16 + n * 16 + border, 0,
minx * -16 + n * 16 + border, border - 1), fill=scalecolor)
minx * -16 + n * 16 + border, border - 1), fill=scalecolor)
for n in range(int(maxz / 4) * 4, minz, -4):
draw.text((2, h - 1 - (n * 16 - minz * 16) + border), str(n * 16),
font=font, fill=scalecolor)
font=font, fill=scalecolor)
draw.line((0, h - 1 - (n * 16 - minz * 16) + border, border - 1,
h - 1 - (n * 16 - minz * 16) + border), fill=scalecolor)
h - 1 - (n * 16 - minz * 16) + border), fill=scalecolor)
if drawplayers:
try:
@ -842,9 +866,10 @@ if drawplayers:
x = (int(float(position[0]) / 10 - minx * 16))
z = int(h - (float(position[2]) / 10 - minz * 16))
draw.ellipse((x - 2 + border, z - 2 + border,
x + 2 + border, z + 2 + border), outline=playercolor)
x + 2 + border, z + 2 + border),
outline=playercolor)
draw.text((x + 2 + border, z + 2 + border), name,
font=font, fill=playercolor)
font=font, fill=playercolor)
f.close()
except OSError:
pass

2
singleimage.py

@ -115,6 +115,8 @@ class ChunkymapOfflineRenderer:
print("")
print("Running")
print(" "+cmd_string)
print(" mapper_path: " + self.minetestmapper_py_path)
print(" backend: " + self.backend_string)
print(" # (this may take a while...)")
if os.path.isfile(tmp_png_path):
os.remove(tmp_png_path)

Loading…
Cancel
Save