102 lines
4.5 KiB
Python
Executable File
102 lines
4.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#Licence LGPL v2.1
|
|
|
|
#https://github.com/minetest/minetest/blob/944ffe9e532a3b2be686ef28c33313148760b1c9/doc/mapformat.txt
|
|
#http://www.tutorialspoint.com/sqlite/sqlite_bitwise_operators.htm
|
|
#http://stackoverflow.com/questions/1294619/does-sqlite-support-any-kind-of-ifcondition-statement-in-a-select
|
|
|
|
import sys #to get parameters
|
|
import sqlite3
|
|
import mt_block_parser
|
|
|
|
import re
|
|
|
|
from PIL import Image, ImageDraw, ImageFont, ImageColor
|
|
|
|
#It is possible to get X, Y, Z directly by SQLite!
|
|
#for row in sourcecursor.execute(" SELECT "+
|
|
# " CASE WHEN `X` < 2048 THEN `X` ELSE `X` - 4096 END AS X, "+
|
|
# " CASE WHEN `Y` < 2048 THEN `Y` ELSE `Y` - 4096 END AS Y, "+
|
|
# " CASE WHEN `Z` < 2048 THEN `Z` ELSE `Z` - 4096 END AS Z "+
|
|
# " FROM ("+"SELECT "+
|
|
# " (`pos`) & 4095 AS X, "+
|
|
# " ((`pos`) & 16773120)>>12 AS Y, "+
|
|
# " ((`pos`) & 68702699520)>>24 AS Z "+
|
|
# " FROM `blocks`"+
|
|
# ")"):
|
|
|
|
source = r'<Put your path to world folder here>/map.sqlite'
|
|
target_image = r'<Put your path to world folder here>/map.png'
|
|
arguments = sys.argv
|
|
if(len(arguments) == 3 ):
|
|
source = str(arguments[1])
|
|
target_image = str(arguments[2])
|
|
|
|
#use compiled regular expression to filter blocks by block content. it is faster that checking "in array".
|
|
useful_block_evidence = re.compile(
|
|
#b"default:cobble|"+"bones:bones|"+
|
|
b"protector:protect|default:chest_locked|doors:door_steel|"+
|
|
b"default:chest|default:torch|default:stonebrick|default:glass|default:obsidian_glass|"+
|
|
b"default:ladder|default:rail|default:fence_wood"
|
|
)
|
|
|
|
sourceconn = sqlite3.connect(source)
|
|
sourcecursorXZ = sourceconn.cursor()
|
|
sourcecursor = sourceconn.cursor()
|
|
|
|
#X and Z min and max to know image size
|
|
for rowMinMax in sourcecursorXZ.execute(" SELECT "+
|
|
" MIN( CASE WHEN `X` < 2048 THEN `X` ELSE `X` - 4096 END ) AS minX, "+
|
|
" MIN( CASE WHEN `Z` < 2048 THEN `Z` ELSE `Z` - 4096 END ) AS minZ, "+
|
|
" MAX( CASE WHEN `X` < 2048 THEN `X` ELSE `X` - 4096 END ) AS maxX, "+
|
|
" MAX( CASE WHEN `Z` < 2048 THEN `Z` ELSE `Z` - 4096 END ) AS maxZ "+
|
|
" FROM ("+"SELECT "+
|
|
" (`pos`) & 4095 AS X, "+
|
|
" ((`pos`) & 68702699520)>>24 AS Z "+
|
|
" FROM `blocks`"+
|
|
")"):
|
|
minX = rowMinMax[0]
|
|
minZ = rowMinMax[1]
|
|
maxX = rowMinMax[2]
|
|
maxZ = rowMinMax[3]
|
|
width = maxZ - minZ
|
|
height = maxX - minX
|
|
|
|
|
|
image = Image.new("RGB", (width, height), (0,0,0,0))
|
|
draw = ImageDraw.Draw(image)
|
|
impixel = image.load()
|
|
|
|
#assuming that map is moustly flat limit Y coordinate
|
|
for row in sourcecursor.execute(" SELECT "+
|
|
" CASE WHEN `X` < 2048 THEN `X` ELSE `X` - 4096 END AS X, "+
|
|
" CASE WHEN `Y` < 2048 THEN `Y` ELSE `Y` - 4096 END AS Y, "+
|
|
" CASE WHEN `Z` < 2048 THEN `Z` ELSE `Z` - 4096 END AS Z, "+
|
|
" `pos`, "+
|
|
" `data` "+
|
|
" FROM ("+"SELECT "+
|
|
" `pos`, "+
|
|
" (`pos`) & 4095 AS X, "+
|
|
" ((`pos`) & 16773120)>>12 AS Y, "+
|
|
" ((`pos`) & 68702699520)>>24 AS Z, "+
|
|
" `data` "+
|
|
" FROM `blocks`"+
|
|
")"+
|
|
" WHERE Y>-5 AND Y<5; "):
|
|
try:
|
|
block = mt_block_parser.MtBlockParser(row[4])
|
|
except:
|
|
print("Block parse error:", row[0], row[1], row[2])
|
|
else:
|
|
if useful_block_evidence.search(block.nameIdMappingsRead)!=None:
|
|
if row[0] - minX < 0 or width <= row[0] - minX or height - row[2] + minZ < 0 or height <= height - row[2] + minZ:
|
|
print("Do not fit to image:", row[0], row[1], row[2])
|
|
else:
|
|
impixel[ row[0] - minX, height - row[2] + minZ ] = (255, 255, 200)
|
|
|
|
|
|
sourceconn.close()
|
|
|
|
draw.ellipse((-minX - 5, height + minZ - 5, -minX + 5, height + minZ + 5), outline=(255, 0, 0)) #map center
|
|
image.save(target_image)
|