|
|
@ -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 |
|
|
|