minetestmapper: Fix the way ylist is computed, use cStringIO instead of rolling own...
authorKahrl <kahrl@gmx.net>
Tue, 27 Sep 2011 00:38:19 +0000 (02:38 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 27 Sep 2011 13:18:22 +0000 (16:18 +0300)
util/minetestmapper.py

index a1f1e3473ff9a039e8bda662dcc4b2c79a282c9e..b4cd2c88f187bc816c399a6939b7a41d3edc3cce 100644 (file)
@@ -29,10 +29,9 @@ import time
 import getopt
 import sys
 import array
+import cStringIO
 from PIL import Image, ImageDraw, ImageFont, ImageColor
 
-CONTENT_WATER = [2, 9]
-
 TRANSLATION_TABLE = {
     1: 0x800,  # CONTENT_GRASS
     4: 0x801,  # CONTENT_TREE
@@ -56,25 +55,6 @@ TRANSLATION_TABLE = {
     28: 0x813,  # CONTENT_PAPYRUS
     29: 0x814}  # CONTENT_BOOKSHELF
 
-class Bytestream:
-    def __init__(self, stream):
-        self.stream = stream
-        self.pos = 0
-        
-        # So you can use files also
-        if hasattr(self.stream, 'read'):
-            self.read = self.stream.read
-    
-    def __len__(self):
-        return len(self.stream)
-    
-    def read(self, length = None):
-        if length is None:
-            length = len(self)
-        self.pos += length
-        return self.stream[self.pos - length:self.pos]
-    
-    def close(self): pass
 
 def hex_to_int(h):
     i = int(h, 16)
@@ -130,14 +110,15 @@ def limit(i, l, h):
 
 
 def usage():
-    print "TODO: Help"
+    print("TODO: Help")
 try:
     opts, args = getopt.getopt(sys.argv[1:], "hi:o:", ["help", "input=",
         "output=", "bgcolor=", "scalecolor=", "origincolor=",
-        "playercolor=", "draworigin", "drawplayers", "drawscale"])
-except getopt.GetoptError, err:
+        "playercolor=", "draworigin", "drawplayers", "drawscale",
+        "drawunderground"])
+except getopt.GetoptError as err:
     # print help information and exit:
-    print str(err)  # will print something like "option -a not recognized"
+    print(str(err))  # will print something like "option -a not recognized"
     usage()
     sys.exit(2)
 
@@ -151,6 +132,7 @@ playercolor = "red"
 drawscale = False
 drawplayers = False
 draworigin = False
+drawunderground = False
 
 sector_xmin = -1500 / 16
 sector_xmax = 1500 / 16
@@ -180,6 +162,8 @@ for o, a in opts:
         drawplayers = True
     elif o == "--draworigin":
         draworigin = True
+    elif o == "--drawunderground":
+        drawunderground = True
     else:
         assert False, "unhandled option"
 
@@ -263,7 +247,7 @@ maxz = max(zlist)
 w = (maxx - minx) * 16 + 16
 h = (maxz - minz) * 16 + 16
 
-print "w=" + str(w) + " h=" + str(h)
+print("w=" + str(w) + " h=" + str(h))
 
 im = Image.new("RGB", (w + border, h + border), bgcolor)
 draw = ImageDraw.Draw(im)
@@ -273,12 +257,15 @@ stuff = {}
 
 starttime = time.time()
 
+CONTENT_WATER = 2
 
-def data_is_air(d):
-    return d in [126, 127, 254]
+def content_is_water(d):
+    return d in [2, 9]
 
+def content_is_air(d):
+    return d in [126, 127, 254]
 
-def read_blocknum(mapdata, version, datapos):
+def read_content(mapdata, version, datapos):
     if version == 20:
         if mapdata[datapos] < 0x80:
             return mapdata[datapos]
@@ -290,7 +277,7 @@ def read_blocknum(mapdata, version, datapos):
         raise Exception("Unsupported map format: " + str(version))
 
 
-def read_mapdata(f, version, pixellist, water):
+def read_mapdata(f, version, pixellist, water, day_night_differs):
     global stuff  # oh my :-)
 
     dec_o = zlib.decompressobj()
@@ -302,34 +289,35 @@ def read_mapdata(f, version, pixellist, water):
     f.close()
 
     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
         chunkzpos = zpos * 16
-        blocknum = 0
+        content = 0
         datapos = 0
         for (x, z) in reversed(pixellist):
             for y in reversed(range(16)):
                 datapos = x + y * 16 + z * 256
-                blocknum = read_blocknum(mapdata, version, datapos)
-                if not data_is_air(blocknum) and blocknum in colors:
-                    if blocknum in CONTENT_WATER:
-                        water[(x, z)] += 1
-                        # Add dummy stuff for drawing sea without seabed
-                        stuff[(chunkxpos + x, chunkzpos + z)] = (
-                            chunkypos + y, blocknum, water[(x, z)])
-                    else:
-                        pixellist.remove((x, z))
-                        # Memorize information on the type and height of
-                        # the block and for drawing the picture.
-                        stuff[(chunkxpos + x, chunkzpos + z)] = (
-                            chunkypos + y, blocknum, water[(x, z)])
-                        break
-                elif not data_is_air(blocknum) and blocknum not in colors:
-                    print "strange block: %s/%s/%s x: %d y: %d z: %d \
-block id: %x" % (xhex, zhex, yhex, x, y, z, blocknum)
+                content = read_content(mapdata, version, datapos)
+                if content_is_air(content):
+                    pass
+                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)
+                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)
+                    pixellist.remove((x, z))
+                    break
+                else:
+                    print("strange block: %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)):
@@ -369,8 +357,9 @@ for n in range(len(xlist)):
     sectortype = ""
 
     if cur:
-        ps = getBlockAsInteger((xpos, 0, zpos))
-        cur.execute("SELECT `pos` FROM `blocks` WHERE `pos`>=? AND `pos`<?", (ps, ps + 4096))
+        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))
         while True:
             r = cur.fetchone()
             if not r:
@@ -404,8 +393,7 @@ for n in range(len(xlist)):
     if sectortype == "":
         continue
 
-       #ylist.sort()
-       ylist = sorted(set(ylist))
+    ylist.sort()
 
     # Make a list of pixels of the sector that are to be looked for.
     pixellist = []
@@ -416,25 +404,22 @@ for n in range(len(xlist)):
             water[(x, z)] = 0
 
     # Go through the Y axis from top to bottom.
-    ylist2 = []
     for ypos in reversed(ylist):
 
         yhex = int_to_hex4(ypos)
 
-        filename = ""
         if sectortype == "sqlite":
             ps = getBlockAsInteger((xpos, ypos, zpos))
             cur.execute("SELECT `data` FROM `blocks` WHERE `pos`==? LIMIT 1", (ps,))
             r = cur.fetchone()
             if not r:
                 continue
-            f = Bytestream(r[0])
+            f = cStringIO.StringIO(r[0])
         else:
             if sectortype == "old":
                 filename = path + "sectors/" + sector1 + "/" + yhex.lower()
             else:
                 filename = path + "sectors2/" + sector2 + "/" + yhex.lower()
-
             f = file(filename, "rb")
 
         # Let's just memorize these even though it's not really necessary.
@@ -442,38 +427,16 @@ for n in range(len(xlist)):
         flags = f.read(1)
 
         # Checking day and night differs -flag
-        if not ord(flags) & 2:
-            ylist2.append((ypos, filename))
-            f.close()
-            continue
+        day_night_differs = ((ord(flags) & 2) != 0)
 
-        read_mapdata(f, version, pixellist, water)
+        read_mapdata(f, version, pixellist, water, day_night_differs)
 
         # 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
 
-    if len(pixellist) > 0:
-        for (ypos, filename) in ylist2:
-            ps = getBlockAsInteger((xpos, ypos, zpos))
-            cur.execute("SELECT `data` FROM `blocks` WHERE `pos`==? LIMIT 1", (ps,))
-            r = cur.fetchone()
-            if not r:
-                continue
-            f = Bytestream(r[0])
-
-            version = ord(f.read(1))
-            flags = f.read(1)
-
-            read_mapdata(f, version, pixellist, water)
-
-            # 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
-
-print "Drawing image"
+print("Drawing image")
 # Drawing the picture
 starttime = time.time()
 n = 0
@@ -499,18 +462,29 @@ for (x, z) in stuff.iterkeys():
     n += 1
 
     (r, g, b) = colors[stuff[(x, z)][1]]
+
+    dnd = stuff[(x, z)][3]  # day/night differs?
+    if not dnd and not drawunderground:
+        if stuff[(x, z)][2] > 0:  # water
+            (r, g, b) = colors[CONTENT_WATER]
+        else:
+            continue
+
     # Comparing heights of a couple of adjacent blocks and changing
     # brightness accordingly.
     try:
+        c = stuff[(x, z)][1]
         c1 = stuff[(x - 1, z)][1]
         c2 = stuff[(x, z + 1)][1]
-        c = stuff[(x, z)][1]
-        if c1 not in CONTENT_WATER and c2 not in CONTENT_WATER and \
-            c not in CONTENT_WATER:
-            y1 = stuff[(x - 1, z)][0]
-            y2 = stuff[(x, z + 1)][0]
+        dnd1 = stuff[(x - 1, z)][3]
+        dnd2 = stuff[(x, z + 1)][3]
+        if not dnd:
+            d = -69
+        elif not content_is_water(c1) and not content_is_water(c2) and \
+            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
             d = ((y - y1) + (y - y2)) * 12
         else:
             d = 0
@@ -567,10 +541,10 @@ if drawplayers:
                 p = string.split(line)
                 if p[0] == "name":
                     name = p[2]
-                    print filename + ": name = " + name
+                    print(filename + ": name = " + name)
                 if p[0] == "position":
                     position = string.split(p[2][1:-1], ",")
-                    print filename + ": position = " + p[2]
+                    print(filename + ": position = " + p[2])
             if len(name) > 0 and len(position) == 3:
                 x = (int(float(position[0]) / 10 - minx * 16))
                 z = int(h - (float(position[2]) / 10 - minz * 16))
@@ -582,5 +556,5 @@ if drawplayers:
     except OSError:
         pass
 
-print "Saving"
+print("Saving")
 im.save(output)