Support backend option and i/o options like the C++ minetestmapper
parent
4502b5565e
commit
fda8d5db15
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -5,6 +5,26 @@ The format is based on [Keep a
|
|||
Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
|
||||
## [git] - 2020-02-29
|
||||
(Poikilos)
|
||||
### Added
|
||||
- Support the `--backend` argument.
|
||||
- Look for it in `get_db`.
|
||||
- Support the `--colors` argument.
|
||||
|
||||
### Changed
|
||||
- Change the `world_dir` argument to `-i` or `--input`.
|
||||
- Allow `-o` as shorthand for `--output`
|
||||
- No longer add `os.path.sep` to `args.input`
|
||||
|
||||
### Fixed
|
||||
- Use `os.path.join`
|
||||
- ...when looking for world.mt if `backend` is not
|
||||
specified in minetestmapper-numpy.py.
|
||||
- No longer add `os.path.sep` to `args.input` and other paths.
|
||||
- Use `elif` with database formats to prevent overlaying converted
|
||||
databases onto each other in minetestmapper-numpy.py.
|
||||
|
||||
## [git] - 2020-02-10
|
||||
(Poikilos)
|
||||
### Removed
|
||||
|
|
|
@ -50,15 +50,17 @@ except ImportError:
|
|||
def join_as_str(delimiter, arr):
|
||||
return delimiter.join(str(x) for x in arr)
|
||||
|
||||
#
|
||||
# wrapper around PIL 1.1.6 Image.save to preserve PNG metadata
|
||||
#
|
||||
# public domain, Nick Galbreath
|
||||
# http://blog.client9.com/2007/08/28/python-pil-and-png-metadata-take-2.html
|
||||
#
|
||||
|
||||
def pngsave(im, file):
|
||||
# these can be automatically added to Image.info dict
|
||||
# they are not user-added metadata
|
||||
"""
|
||||
This is a wrapper around PIL 1.1.6 Image.save to preserve PNG
|
||||
metadata.
|
||||
CC0 Nick Galbreath
|
||||
<http://blog.client9.com/2007/08/28/
|
||||
python-pil-and-png-metadata-take-2.html>
|
||||
These can be automatically added to Image.info dict.
|
||||
They are not user-added metadata.
|
||||
"""
|
||||
reserved = ('interlace', 'gamma', 'dpi', 'transparency', 'aspect')
|
||||
|
||||
# undocumented class
|
||||
|
@ -139,11 +141,14 @@ def int_to_hex4(i):
|
|||
# return i
|
||||
# else:
|
||||
# return i + 2*max_positive
|
||||
|
||||
|
||||
# def getBlockAsInteger(p):
|
||||
# return signedToUnsigned(p[2],2048)*16777216
|
||||
# + signedToUnsigned(p[1],2048)*4096
|
||||
# + signedToUnsigned(p[0],2048)
|
||||
|
||||
|
||||
def getBlockAsInteger(p):
|
||||
return p[2]*16777216 + p[1]*4096 + p[0]
|
||||
|
||||
|
@ -307,29 +312,30 @@ def parse_args():
|
|||
help=('accepted for compatibility but'
|
||||
' NOT YET IMPLEMENTED in this version'))
|
||||
ap.add_argument('--colors', type=str, default='colors.txt',
|
||||
help=('accepted for compatibility but'
|
||||
' NOT YET IMPLEMENTED in this version'))
|
||||
ap.add_argument('--backend', type=str, choices=('leveldb'),
|
||||
default='leveldb',
|
||||
help=('specify a colors list in colors.txt format'
|
||||
'"80c 183 183 222 # CONTENT_GLASS"'
|
||||
'or "default:stone 128 128 128")'))
|
||||
ap.add_argument('--backend', type=str,
|
||||
choices=('leveldb', 'sqlite3'), default='leveldb',
|
||||
help=('accepted for compatibility but'
|
||||
' NOT YET IMPLEMENTED in this version'))
|
||||
ap.add_argument('--fog', type=float, metavar=('FOGSTRENGTH'),
|
||||
default=0.0, help=('use fog strength of'
|
||||
' FOGSTRENGTH (0.0 by'
|
||||
' default, max of 1.0)'))
|
||||
ap.add_argument('world_dir',
|
||||
ap.add_argument('-i', '--input',
|
||||
help='the path to the world you want to map')
|
||||
ap.add_argument('output', nargs='?', default='map.png',
|
||||
ap.add_argument('-o', '--output', nargs="?", default='map.png',
|
||||
help='the output filename')
|
||||
args = ap.parse_args()
|
||||
if args.world_dir is None:
|
||||
if args.input is None:
|
||||
print("Please select world path (eg. -i ../worlds/yourworld)"
|
||||
" (or use --help)")
|
||||
sys.exit(1)
|
||||
if not os.path.isdir(args.world_dir):
|
||||
if not os.path.isdir(args.input):
|
||||
print("World does not exist")
|
||||
sys.exit(1)
|
||||
args.world_dir = os.path.abspath(args.world_dir) + os.path.sep
|
||||
args.input = os.path.abspath(args.input)
|
||||
return args
|
||||
|
||||
|
||||
|
@ -376,19 +382,21 @@ def load_colors(fname="colors.txt"):
|
|||
def legacy_fetch_sector_data(args, sectortype, sector_data, ypos):
|
||||
yhex = int_to_hex4(ypos)
|
||||
if sectortype == "old":
|
||||
ss_path = args.world_dir + "sectors/"
|
||||
filename = ss_path + sector_data[0] + "/" + yhex.lower()
|
||||
ss_path = os.path.join(args.input, "sectors")
|
||||
filename = os.path.join(ss_path, sector_data[0], + yhex.lower())
|
||||
else:
|
||||
ss2_path = args.world_dir + "sectors2/"
|
||||
filename = ss2_path + sector_data[1] + "/" + yhex.lower()
|
||||
ss2_path = os.path.join(args.input, "sectors2")
|
||||
filename = os.path.join(ss2_path, sector_data[1], yhex.lower())
|
||||
return open(filename, "rb")
|
||||
|
||||
|
||||
def legacy_sector_scan(args, sectors_xmin, sector_xmax, sector_zmin,
|
||||
sector_zmax):
|
||||
if os.path.exists(args.world_dir + "sectors2"):
|
||||
for filename in os.listdir(args.world_dir + "sectors2"):
|
||||
ss2_f_path = args.world_dir + "sectors2/" + filename
|
||||
ss_path = os.path.join(args.input, "sectors")
|
||||
ss2_path = os.path.join(args.input, "sectors2")
|
||||
if os.path.exists(ss2_path):
|
||||
for filename in os.listdir(ss2_path):
|
||||
ss2_f_path = os.path.join(ss2_path, filename)
|
||||
for filename2 in os.listdir(ss2_f_path):
|
||||
x = hex_to_int(filename)
|
||||
z = hex_to_int(filename2)
|
||||
|
@ -398,9 +406,8 @@ def legacy_sector_scan(args, sectors_xmin, sector_xmax, sector_zmin,
|
|||
continue
|
||||
xlist.append(x)
|
||||
zlist.append(z)
|
||||
|
||||
if os.path.exists(args.world_dir + "sectors"):
|
||||
for filename in os.listdir(args.world_dir + "sectors"):
|
||||
elif os.path.exists(ss_path):
|
||||
for filename in os.listdir(ss_path):
|
||||
x = hex4_to_int(filename[:4])
|
||||
z = hex4_to_int(filename[-4:])
|
||||
if x < sector_xmin or x > sector_xmax:
|
||||
|
@ -419,13 +426,15 @@ def legacy_fetch_ylist(args, xpos, zpos, ylist):
|
|||
zhex4 = int_to_hex4(zpos)
|
||||
|
||||
sector1 = xhex4.lower() + zhex4.lower()
|
||||
sector2 = xhex.lower() + "/" + zhex.lower()
|
||||
sector2 = os.path.join(xhex.lower(), zhex.lower())
|
||||
ss_path = os.path.join(args.input, "sectors")
|
||||
ss2_path = os.path.join(args.input, "sectors2")
|
||||
try:
|
||||
ss_s1_path = args.world_dir + "sectors/" + sector1
|
||||
ss_s1_path = ss_path + sector1
|
||||
for filename in os.listdir(ss_s1_path):
|
||||
if(filename != "meta"):
|
||||
if (filename != "meta"):
|
||||
pos = int(filename, 16)
|
||||
if(pos > 32767):
|
||||
if (pos > 32767):
|
||||
pos -= 65536
|
||||
ylist.append(pos)
|
||||
|
||||
|
@ -434,11 +443,11 @@ def legacy_fetch_ylist(args, xpos, zpos, ylist):
|
|||
|
||||
if sectortype == "":
|
||||
try:
|
||||
ss2_s2_path = args.world_dir + "sectors2/" + sector2
|
||||
ss2_s2_path = os.path.join(ss2_path, sector2)
|
||||
for filename in os.listdir(ss2_s2_path):
|
||||
if(filename != "meta"):
|
||||
if (filename != "meta"):
|
||||
pos = int(filename, 16)
|
||||
if(pos > 32767):
|
||||
if (pos > 32767):
|
||||
pos -= 65536
|
||||
ylist.append(pos)
|
||||
sectortype = "new"
|
||||
|
@ -551,20 +560,25 @@ def map_block_ug(mapdata, version, ypos, maxy, cdata, hdata, udata,
|
|||
|
||||
|
||||
def get_db(args):
|
||||
if not os.path.exists(args.world_dir+"world.mt"):
|
||||
return None
|
||||
with open(args.world_dir+"world.mt") as f:
|
||||
keyvals = f.read().splitlines()
|
||||
keyvals = [kv.split("=") for kv in keyvals]
|
||||
backend = None
|
||||
for k, v in keyvals:
|
||||
if k.strip() == "backend":
|
||||
backend = v.strip()
|
||||
break
|
||||
backend = args.backend
|
||||
if args.backend is None:
|
||||
# This should never happen.
|
||||
print("* detecting db type from world.mt in "
|
||||
"{}".format(args.input))
|
||||
if not os.path.exists(os.path.join(args.input, "world.mt")):
|
||||
return None
|
||||
with open(os.path.join(args.input, "world.mt")) as f:
|
||||
keyvals = f.read().splitlines()
|
||||
keyvals = [kv.split("=") for kv in keyvals]
|
||||
backend = None
|
||||
for k, v in keyvals:
|
||||
if k.strip() == "backend":
|
||||
backend = v.strip()
|
||||
break
|
||||
if backend == "sqlite3":
|
||||
return SQLDB(args.world_dir + "map.sqlite")
|
||||
return SQLDB(os.path.join(args.input, "map.sqlite"))
|
||||
if backend == "leveldb":
|
||||
return LVLDB(args.world_dir + "map.db")
|
||||
return LVLDB(os.path.join(args.input, "map.db"))
|
||||
|
||||
|
||||
class SQLDB:
|
||||
|
@ -1299,8 +1313,9 @@ def draw_image(world, uid_to_color):
|
|||
|
||||
if args.drawplayers:
|
||||
try:
|
||||
for filename in os.listdir(args.world_dir + "players"):
|
||||
f = open(args.world_dir + "players/" + filename)
|
||||
players_path = os.path.join(args.input, "players")
|
||||
for filename in os.listdir(players_path):
|
||||
f = open(os.path.join(players_path, filename))
|
||||
lines = f.readlines()
|
||||
name = ""
|
||||
position = []
|
||||
|
@ -1395,7 +1410,7 @@ def draw_image(world, uid_to_color):
|
|||
def main():
|
||||
args = parse_args()
|
||||
|
||||
uid_to_color, str_to_uid = load_colors()
|
||||
uid_to_color, str_to_uid = load_colors(fname=args.colors)
|
||||
|
||||
world = World(args)
|
||||
|
||||
|
|
|
@ -148,6 +148,13 @@ def readS32(f):
|
|||
ord(f.read(1)), 2**31)
|
||||
|
||||
|
||||
colors_msg = """<color> format: '#000000'
|
||||
NOTE: colors.txt must be in same directory as
|
||||
this script or in the current working
|
||||
directory (or util directory if installed).
|
||||
Otherwise, use the --colors option followed by a path.
|
||||
"""
|
||||
|
||||
usagetext = """minetestmapper.py [options]
|
||||
-i/--input <world_path>
|
||||
-o/--output <output_image.png>
|
||||
|
@ -161,10 +168,8 @@ usagetext = """minetestmapper.py [options]
|
|||
--region <xmin>:<xmax>,<zmin>:<zmax>
|
||||
--geometry <xmin>:<zmin>+<width>+<height>
|
||||
--drawunderground
|
||||
Color format: '#000000'
|
||||
NOTE: colors.txt must be in same directory as
|
||||
this script or in the current working
|
||||
directory (or util directory if installed).
|
||||
--colors <path to colors.txt>
|
||||
--backend <sqlite3> (other db formats are NOT YET IMPLEMENTED)
|
||||
"""
|
||||
|
||||
|
||||
|
@ -179,7 +184,7 @@ try:
|
|||
"bgcolor=", "scalecolor=", "origincolor=",
|
||||
"playercolor=", "draworigin", "drawplayers",
|
||||
"drawscale", "drawunderground", "geometry=",
|
||||
"region="])
|
||||
"region=", "colors=", "backend="])
|
||||
except getopt.GetoptError as err:
|
||||
# print help information and exit:
|
||||
print(str(err)) # something like "option -a not recognized"
|
||||
|
@ -199,6 +204,7 @@ draworigin = False
|
|||
drawunderground = False
|
||||
geometry_string = None
|
||||
region_string = None
|
||||
colors_path = None
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-h", "--help"):
|
||||
|
@ -229,6 +235,8 @@ for o, a in opts:
|
|||
geometry_string = a
|
||||
elif o == "--region":
|
||||
region_string = a
|
||||
elif o == "--colors":
|
||||
colors_path = a
|
||||
elif o == "--drawalpha":
|
||||
print("# ignored (NOT YET IMPLEMENTED) " + o)
|
||||
elif o == "--noshading":
|
||||
|
@ -241,8 +249,6 @@ for o, a in opts:
|
|||
print("# ignored (NOT YET IMPLEMENTED) " + o)
|
||||
elif o == "--zoom":
|
||||
print("# ignored (NOT YET IMPLEMENTED) " + o)
|
||||
elif o == "--colors":
|
||||
print("# ignored (NOT YET IMPLEMENTED) " + o)
|
||||
elif o == "--scales":
|
||||
print("# ignored (NOT YET IMPLEMENTED) " + o)
|
||||
else:
|
||||
|
@ -325,7 +331,7 @@ if path[-1:] != "/" and path[-1:] != "\\":
|
|||
|
||||
# Load color information for the blocks.
|
||||
colors = {}
|
||||
colors_path = "colors.txt"
|
||||
colors_name = "colors.txt"
|
||||
|
||||
profile_path = None
|
||||
if 'HOME' in os.environ:
|
||||
|
@ -335,24 +341,27 @@ elif 'USERPROFILE' in os.environ:
|
|||
|
||||
mt_path = None
|
||||
mt_util_path = None
|
||||
abs_colors_path = None
|
||||
|
||||
if not os.path.isfile(colors_path):
|
||||
colors_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
"colors.txt")
|
||||
try_dot_mt_path = os.path.join(profile_path, ".minetest")
|
||||
mt_path = os.path.join(profile_path, "minetest")
|
||||
mt_util_path = os.path.join(mt_path, "util")
|
||||
|
||||
if not os.path.isfile(colors_path):
|
||||
if profile_path is not None:
|
||||
try_path = os.path.join(profile_path, "minetest")
|
||||
if os.path.isdir(try_path):
|
||||
mt_path = try_path
|
||||
mt_util_path = os.path.join(mt_path, "util")
|
||||
abs_colors_path = os.path.join(mt_util_path, "colors.txt")
|
||||
if os.path.isfile(abs_colors_path):
|
||||
colors_path = abs_colors_path
|
||||
if colors_path is None:
|
||||
try_paths = []
|
||||
try_paths.append(try_dot_mt_path, colors_name)
|
||||
try_paths.append(
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
colors_name)
|
||||
)
|
||||
try_paths.append(mt_path, colors_name)
|
||||
try_paths.append(mt_util_path, colors_name)
|
||||
for try_path in try_paths:
|
||||
if os.path.isfile(try_path):
|
||||
colos_path = try_path
|
||||
break
|
||||
|
||||
if not os.path.isfile(colors_path):
|
||||
print("ERROR: could not find colors.txt")
|
||||
if (colors_path is None) or (not os.path.isfile(colors_path)):
|
||||
print("ERROR: could not find {}".format(colors_name))
|
||||
usage()
|
||||
sys.exit(1)
|
||||
|
||||
|
@ -360,7 +369,7 @@ try:
|
|||
f = open(colors_path)
|
||||
except IOError:
|
||||
f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
"colors.txt"))
|
||||
colors_name))
|
||||
for line in f:
|
||||
values = line.split()
|
||||
if len(values) < 4:
|
||||
|
@ -394,6 +403,8 @@ zlist = []
|
|||
|
||||
conn = None
|
||||
cur = None
|
||||
look_for_names = ["map.sqlite", "sectors2", "sectors"]
|
||||
look_for_paths = [os.path.join(path, x) for x in look_for_names]
|
||||
if os.path.exists(path + "map.sqlite"):
|
||||
import sqlite3
|
||||
conn = sqlite3.connect(path + "map.sqlite")
|
||||
|
@ -414,8 +425,7 @@ if os.path.exists(path + "map.sqlite"):
|
|||
|
||||
xlist.append(x)
|
||||
zlist.append(z)
|
||||
|
||||
if os.path.exists(path + "sectors2"):
|
||||
elif os.path.exists(path + "sectors2"):
|
||||
for filename in os.listdir(path + "sectors2"):
|
||||
for filename2 in os.listdir(path + "sectors2/" + filename):
|
||||
x = hex_to_int(filename)
|
||||
|
@ -426,8 +436,7 @@ if os.path.exists(path + "sectors2"):
|
|||
continue
|
||||
xlist.append(x)
|
||||
zlist.append(z)
|
||||
|
||||
if os.path.exists(path + "sectors"):
|
||||
elif os.path.exists(path + "sectors"):
|
||||
for filename in os.listdir(path + "sectors"):
|
||||
x = hex4_to_int(filename[:4])
|
||||
z = hex4_to_int(filename[-4:])
|
||||
|
@ -439,7 +448,8 @@ if os.path.exists(path + "sectors"):
|
|||
zlist.append(z)
|
||||
|
||||
if len(xlist) == 0 or len(zlist) == 0:
|
||||
print("Data does not exist at this location.")
|
||||
print("A compatible database was not found ({})."
|
||||
"".format(look_for_paths))
|
||||
sys.exit(1)
|
||||
|
||||
# Get rid of doubles
|
||||
|
@ -703,7 +713,8 @@ for n in range(len(xlist)):
|
|||
# zlib-compressed node metadata list
|
||||
dec_o = zlib.decompressobj()
|
||||
try:
|
||||
metaliststr = array.array("B", dec_o.decompress(f.read()))
|
||||
metaliststr = array.array("B",
|
||||
dec_o.decompress(f.read()))
|
||||
# And do nothing with it
|
||||
except:
|
||||
metaliststr = []
|
||||
|
|
47
quality.sh
47
quality.sh
|
@ -1,31 +1,34 @@
|
|||
#!/bin/sh
|
||||
if [ ! -f "`command -v pycodestyle-3`" ]; then
|
||||
echo "You must install the python3-pycodestyle package before using the quality script."
|
||||
exit 1
|
||||
echo "You must install the python3-pycodestyle package before using the quality script."
|
||||
exit 1
|
||||
fi
|
||||
target="minetestmapper-numpy.py"
|
||||
# target="__init__.py"
|
||||
# if [ ! -z "$1" ]; then
|
||||
# target="$1"
|
||||
# target="$1"
|
||||
# fi
|
||||
if [ -f err.txt ]; then
|
||||
rm err.txt
|
||||
fi
|
||||
if [ -f "`command -v outputinspector`" ]; then
|
||||
pycodestyle-3 "minetestmapper.py" > err.txt
|
||||
pycodestyle-3 "$target" >> err.txt
|
||||
# For one-liner, would use `||` not `&&`, because pycodestyle-3 returns nonzero (error state) if there are any errors
|
||||
if [ -s "err.txt" ]; then
|
||||
outputinspector
|
||||
else
|
||||
echo "No quality issues were detected."
|
||||
rm err.txt
|
||||
# echo "Deleted empty 'err.txt'."
|
||||
fi
|
||||
else
|
||||
pycodestyle-3 "minetestmapper.py"
|
||||
pycodestyle-3 "$target"
|
||||
echo
|
||||
echo "If you install outputinspector, this output can be examined automatically, allowing double-click to skip to line in Geany/Kate"
|
||||
echo
|
||||
fi
|
||||
ext="py"
|
||||
if [ -f "`command -v outputinspector`" ]; then
|
||||
for f in *.$ext; do
|
||||
pycodestyle-3 "$f" >> err.txt
|
||||
done
|
||||
# For one-liner, would use `||` not `&&`, because pycodestyle-3 returns nonzero (error state) if there are any errors
|
||||
if [ -s "err.txt" ]; then
|
||||
# -s: exists and >0 bytes
|
||||
outputinspector
|
||||
else
|
||||
echo "No quality issues were detected."
|
||||
rm err.txt
|
||||
# echo "Deleted empty 'err.txt'."
|
||||
fi
|
||||
else
|
||||
for f in *.$ext; do
|
||||
pycodestyle-3 "$f" >> err.txt
|
||||
done
|
||||
echo
|
||||
echo "If you install outputinspector, this output can be examined automatically, allowing double-click to skip to line in Geany/Kate"
|
||||
echo
|
||||
fi
|
||||
|
|
Loading…
Reference in New Issue