updated and cleaned up overviewer.py
- moved c_overviewer version checks into __init__.py - bare_console support (mostly) moved into util, slightly more sane - removed and updated a ton of old code
This commit is contained in:
329
overviewer.py
329
overviewer.py
@@ -18,25 +18,13 @@
|
|||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
# quick version check
|
||||||
if not (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
|
if not (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
|
||||||
print "Sorry, the Overviewer requires at least Python 2.6 to run"
|
print "Sorry, the Overviewer requires at least Python 2.6 to run"
|
||||||
if sys.version_info[0] >= 3:
|
if sys.version_info[0] >= 3:
|
||||||
print "and will not run on Python 3.0 or later"
|
print "and will not run on Python 3.0 or later"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
isBareConsole = False
|
|
||||||
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
try:
|
|
||||||
import ctypes
|
|
||||||
GetConsoleProcessList = ctypes.windll.kernel32.GetConsoleProcessList
|
|
||||||
num = GetConsoleProcessList(ctypes.byref(ctypes.c_int(0)), ctypes.c_int(1))
|
|
||||||
if (num == 1):
|
|
||||||
isBareConsole = True
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
@@ -44,110 +32,13 @@ import subprocess
|
|||||||
import multiprocessing
|
import multiprocessing
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
from overviewer_core import util
|
|
||||||
|
|
||||||
def doExit(msg=None, code=1, wait=None, consoleMsg=True):
|
|
||||||
'''Exits Overviewer. If `wait` is None, the default
|
|
||||||
will be true is 'isBareConsole' is true'''
|
|
||||||
global isBareConsole
|
|
||||||
if msg:
|
|
||||||
print msg
|
|
||||||
|
|
||||||
if wait == None:
|
|
||||||
if isBareConsole:
|
|
||||||
if consoleMsg:
|
|
||||||
print "\n"
|
|
||||||
print "The Overviewer is a console program. Please open a Windows command prompt"
|
|
||||||
print "first and run Overviewer from there. Further documentation is available at"
|
|
||||||
print "http://docs.overviewer.org/\n"
|
|
||||||
print "Press [Enter] to close this window."
|
|
||||||
raw_input()
|
|
||||||
else:
|
|
||||||
if wait:
|
|
||||||
if consoleMsg:
|
|
||||||
print "\n"
|
|
||||||
print "The Overviewer is a console program. Please open a Windows command prompt"
|
|
||||||
print "first and run Overviewer from there. Further documentation is available at"
|
|
||||||
print "http://docs.overviewer.org/\n"
|
|
||||||
print "Press [Enter] to close this window."
|
|
||||||
raw_input()
|
|
||||||
|
|
||||||
sys.exit(code)
|
|
||||||
|
|
||||||
|
|
||||||
this_dir = util.get_program_path()
|
|
||||||
|
|
||||||
# make sure the c_overviewer extension is available
|
|
||||||
try:
|
|
||||||
from overviewer_core import c_overviewer
|
|
||||||
except ImportError:
|
|
||||||
## if this is a frozen windows package, the following error messages about
|
|
||||||
## building the c_overviewer extension are not appropriate
|
|
||||||
if hasattr(sys, "frozen"):
|
|
||||||
print "Something has gone wrong importing the c_overviewer extension. Please"
|
|
||||||
print "make sure the 2008 and 2010 redistributable packages from Microsoft"
|
|
||||||
print "are installed."
|
|
||||||
doExit()
|
|
||||||
|
|
||||||
|
|
||||||
## try to find the build extension
|
|
||||||
ext = os.path.join(this_dir, "overviewer_core", "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
|
|
||||||
if os.path.exists(ext):
|
|
||||||
print "Something has gone wrong importing the c_overviewer extension. Please"
|
|
||||||
print "make sure it is up-to-date (clean and rebuild)"
|
|
||||||
doExit()
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
print ""
|
|
||||||
print "You need to compile the c_overviewer module to run Minecraft Overviewer."
|
|
||||||
print "Run `python setup.py build`, or see the README for details."
|
|
||||||
doExit()
|
|
||||||
|
|
||||||
from overviewer_core import textures
|
|
||||||
|
|
||||||
if hasattr(sys, "frozen"):
|
|
||||||
pass # we don't bother with a compat test since it should always be in sync
|
|
||||||
elif "extension_version" in dir(c_overviewer):
|
|
||||||
# check to make sure the binary matches the headers
|
|
||||||
if os.path.exists(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")):
|
|
||||||
with open(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")) as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
|
|
||||||
if lines:
|
|
||||||
l = lines[0]
|
|
||||||
if int(l.split()[2].strip()) != c_overviewer.extension_version():
|
|
||||||
print "Please rebuild your c_overviewer module. It is out of date!"
|
|
||||||
doExit(code=1, consoleMsg=True)
|
|
||||||
else:
|
|
||||||
print "Please rebuild your c_overviewer module. It is out of date!"
|
|
||||||
doExit()
|
|
||||||
|
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
from overviewer_core import util
|
||||||
|
from overviewer_core import textures
|
||||||
from overviewer_core import optimizeimages, world
|
from overviewer_core import optimizeimages, world
|
||||||
#from overviewer_core import googlemap
|
|
||||||
from overviewer_core import configParser, tileset, assetmanager, dispatcher
|
from overviewer_core import configParser, tileset, assetmanager, dispatcher
|
||||||
|
|
||||||
# definitions of built-in custom modes
|
|
||||||
# usually because what used to be a mode became an option
|
|
||||||
# for example, night mode
|
|
||||||
builtin_custom_rendermodes = {}
|
|
||||||
# 'night' : {
|
|
||||||
# 'parent' : 'lighting',
|
|
||||||
# 'label' : 'Night',
|
|
||||||
# 'description' : 'like "lighting", except at night',
|
|
||||||
# 'options' : {'night' : True}
|
|
||||||
# },
|
|
||||||
|
|
||||||
# 'smooth-night' : {
|
|
||||||
# 'parent' : 'smooth-lighting',
|
|
||||||
# 'label' : 'Smooth Night',
|
|
||||||
# 'description' : 'like "lighting", except smooth and at night',
|
|
||||||
# 'options' : {'night' : True}
|
|
||||||
# },
|
|
||||||
# }
|
|
||||||
|
|
||||||
helptext = """
|
helptext = """
|
||||||
%prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir>"""
|
%prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir>"""
|
||||||
|
|
||||||
@@ -195,7 +86,6 @@ def configure_logger(loglevel=logging.INFO, verbose=False):
|
|||||||
logger.setLevel(loglevel)
|
logger.setLevel(loglevel)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# bootstrap the logger with defaults
|
# bootstrap the logger with defaults
|
||||||
configure_logger()
|
configure_logger()
|
||||||
|
|
||||||
@@ -216,7 +106,6 @@ def main():
|
|||||||
#parser.add_option("--forcerender", dest="forcerender", help="Force re-rendering the entire map (or the given regionlist). Useful for re-rendering without deleting it.", action="store_true")
|
#parser.add_option("--forcerender", dest="forcerender", help="Force re-rendering the entire map (or the given regionlist). Useful for re-rendering without deleting it.", action="store_true")
|
||||||
#parser.add_option("--stochastic-render", dest="stochastic_render", help="Rerender a non-updated tile randomly, with the given probability (between 0 and 1). Useful for incrementally updating a map with a new mode.", type="float", advanced=True, default=0.0, metavar="PROBABILITY")
|
#parser.add_option("--stochastic-render", dest="stochastic_render", help="Rerender a non-updated tile randomly, with the given probability (between 0 and 1). Useful for incrementally updating a map with a new mode.", type="float", advanced=True, default=0.0, metavar="PROBABILITY")
|
||||||
#parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by ',', ':', or '/'. Use --list-rendermodes to list them all.", type="choice", required=True, default=avail_rendermodes[0], listify=True)
|
#parser.add_option("--rendermodes", dest="rendermode", help="Specifies the render types, separated by ',', ':', or '/'. Use --list-rendermodes to list them all.", type="choice", required=True, default=avail_rendermodes[0], listify=True)
|
||||||
parser.add_option("--list-rendermodes", dest="list_rendermodes", action="store_true", help="List available render modes and exit.")
|
|
||||||
#parser.add_option("--rendermode-options", dest="rendermode_options", default={}, advanced=True, help="Used to specify options for different rendermodes. Only useful in a settings.py file")
|
#parser.add_option("--rendermode-options", dest="rendermode_options", default={}, advanced=True, help="Used to specify options for different rendermodes. Only useful in a settings.py file")
|
||||||
#parser.add_option("--custom-rendermodes", dest="custom_rendermodes", default={}, advanced=True, help="Used to define custom rendermodes. Only useful in a settings.py file")
|
#parser.add_option("--custom-rendermodes", dest="custom_rendermodes", default={}, advanced=True, help="Used to define custom rendermodes. Only useful in a settings.py file")
|
||||||
#parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", advanced=True )
|
#parser.add_option("--imgformat", dest="imgformat", help="The image output format to use. Currently supported: png(default), jpg.", advanced=True )
|
||||||
@@ -253,59 +142,54 @@ def main():
|
|||||||
print "Build machine: %s %s" % (overviewer_version.BUILD_PLATFORM, overviewer_version.BUILD_OS)
|
print "Build machine: %s %s" % (overviewer_version.BUILD_PLATFORM, overviewer_version.BUILD_OS)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print "(build info not found)"
|
print "(build info not found)"
|
||||||
pass
|
return 0
|
||||||
doExit(code=0, consoleMsg=False)
|
|
||||||
|
|
||||||
# setup c_overviewer rendermode customs / options
|
|
||||||
for mode in builtin_custom_rendermodes:
|
|
||||||
c_overviewer.add_custom_render_mode(mode, builtin_custom_rendermodes[mode])
|
|
||||||
# TODO allow custom rendermodes to be specified in a settings.py file
|
|
||||||
#for mode in options.custom_rendermodes:
|
|
||||||
# c_overviewer.add_custom_render_mode(mode, options.custom_rendermodes[mode])
|
|
||||||
#for mode in options.rendermode_options:
|
|
||||||
# c_overviewer.set_render_mode_options(mode, options.rendermode_options[mode])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if options.list_rendermodes:
|
|
||||||
list_rendermodes()
|
|
||||||
doExit(code=0, consoleMsg=False)
|
|
||||||
|
|
||||||
if options.check_terrain:
|
if options.check_terrain:
|
||||||
import hashlib
|
import hashlib
|
||||||
from overviewer_core.textures import _find_file
|
from overviewer_core.textures import Textures
|
||||||
if options.textures_path:
|
# TODO custom textures path?
|
||||||
textures._find_file_local_path = options.textures_path
|
tex = Textures()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = _find_file("terrain.png", verbose=True)
|
f = tex.find_file("terrain.png", verbose=True)
|
||||||
except IOError:
|
except IOError:
|
||||||
logging.error("Could not find the file terrain.png")
|
logging.error("Could not find the file terrain.png")
|
||||||
doExit(code=1, consoleMsg=False)
|
return 1
|
||||||
|
|
||||||
h = hashlib.sha1()
|
h = hashlib.sha1()
|
||||||
h.update(f.read())
|
h.update(f.read())
|
||||||
logging.info("Hash of terrain.png file is: `%s`", h.hexdigest())
|
logging.info("Hash of terrain.png file is: `%s`", h.hexdigest())
|
||||||
doExit(code=0, consoleMsg=False)
|
return 0
|
||||||
|
|
||||||
|
if options.display_config:
|
||||||
|
# just display the config file and exit
|
||||||
|
parser.display_config()
|
||||||
|
return 0
|
||||||
|
|
||||||
# TODO remove advanced help? needs discussion
|
# TODO remove advanced help? needs discussion
|
||||||
#if options.advanced_help:
|
|
||||||
# parser.advanced_help()
|
|
||||||
# doExit(code=0, consoleMsg=False)
|
|
||||||
|
|
||||||
# TODO right now, we will not let users specify worlds to render on the command line.
|
# TODO right now, we will not let users specify worlds to render on the command line.
|
||||||
# TODO in the future, we need to also let worlds be specified on the command line
|
# TODO in the future, we need to also let worlds be specified on the command line
|
||||||
|
|
||||||
|
# if no arguments are provided, print out a helpful message
|
||||||
|
if len(args) == 0:
|
||||||
|
# first provide an appropriate error for bare-console users
|
||||||
|
# that don't provide any options
|
||||||
|
if util.is_bare_console():
|
||||||
|
print "\n"
|
||||||
|
print "The Overviewer is a console program. Please open a Windows command prompt"
|
||||||
|
print "first and run Overviewer from there. Further documentation is available at"
|
||||||
|
print "http://docs.overviewer.org/\n"
|
||||||
|
else:
|
||||||
|
# more helpful message for users who know what they're doing
|
||||||
|
logging.error("You need to give me your world number or directory")
|
||||||
|
parser.print_help()
|
||||||
|
list_worlds()
|
||||||
|
return 1
|
||||||
|
|
||||||
# for multiworld, we must specify the *outputdir* on the command line
|
# for multiworld, we must specify the *outputdir* on the command line
|
||||||
if len(args) == 1:
|
elif len(args) == 1:
|
||||||
logging.debug("Using %r as the output_directory", args[0])
|
logging.debug("Using %r as the output_directory", args[0])
|
||||||
destdir = os.path.expanduser(args[0])
|
destdir = os.path.expanduser(args[0])
|
||||||
|
|
||||||
elif len(args) < 1:
|
|
||||||
logging.error("You need to give me your world number or directory")
|
|
||||||
parser.print_help()
|
|
||||||
list_worlds()
|
|
||||||
doExit(code=1, consoleMsg=True)
|
|
||||||
elif len(args) == 2: # TODO support this usecase
|
elif len(args) == 2: # TODO support this usecase
|
||||||
worlddir = os.path.expanduser(args[0])
|
worlddir = os.path.expanduser(args[0])
|
||||||
destdir = os.path.expanduser(args[1])
|
destdir = os.path.expanduser(args[1])
|
||||||
@@ -319,14 +203,7 @@ def main():
|
|||||||
if os.path.exists(" ".join(args[start:end])):
|
if os.path.exists(" ".join(args[start:end])):
|
||||||
logging.warning("It looks like you meant to specify \"%s\" as your world dir or your output\n\
|
logging.warning("It looks like you meant to specify \"%s\" as your world dir or your output\n\
|
||||||
dir but you forgot to put quotes around the directory, since it contains spaces." % " ".join(args[start:end]))
|
dir but you forgot to put quotes around the directory, since it contains spaces." % " ".join(args[start:end]))
|
||||||
doExit(code=1, consoleMsg=False)
|
return 1
|
||||||
|
|
||||||
|
|
||||||
if options.display_config:
|
|
||||||
# just display the config file and exit
|
|
||||||
parser.display_config()
|
|
||||||
doExit(code=0, consoleMsg=False)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO regionlists are per-world
|
# TODO regionlists are per-world
|
||||||
#if options.regionlist:
|
#if options.regionlist:
|
||||||
@@ -363,11 +240,11 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
# except IOError as e:
|
# except IOError as e:
|
||||||
# logging.error("Unable to open file %s to use for changelist." % options.changelist)
|
# logging.error("Unable to open file %s to use for changelist." % options.changelist)
|
||||||
# logging.error("I/O Error: %s" % e.strerror)
|
# logging.error("I/O Error: %s" % e.strerror)
|
||||||
# doExit(code=1, consoleMsg=False)
|
# return 1
|
||||||
|
|
||||||
#if options.changelist_format != "auto" and not options.changelist:
|
#if options.changelist_format != "auto" and not options.changelist:
|
||||||
# logging.error("changelist_format specified without changelist.")
|
# logging.error("changelist_format specified without changelist.")
|
||||||
# doExit(code=1, consoleMsg=False)
|
# return 1
|
||||||
#if options.changelist_format == "auto":
|
#if options.changelist_format == "auto":
|
||||||
# options.changelist_format = "relative"
|
# options.changelist_format = "relative"
|
||||||
|
|
||||||
@@ -382,7 +259,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
tex.generate()
|
tex.generate()
|
||||||
except IOError, e:
|
except IOError, e:
|
||||||
logging.error(str(e))
|
logging.error(str(e))
|
||||||
doExit(code=1, consoleMsg=False)
|
return 1
|
||||||
|
|
||||||
# look at our settings.py file
|
# look at our settings.py file
|
||||||
mw_parser = configParser.MultiWorldParser("settings.py")
|
mw_parser = configParser.MultiWorldParser("settings.py")
|
||||||
@@ -429,127 +306,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
dispatch.close()
|
dispatch.close()
|
||||||
|
|
||||||
assetMrg.finalize(tilesets)
|
assetMrg.finalize(tilesets)
|
||||||
|
return 0
|
||||||
sys.exit("early abort")
|
|
||||||
|
|
||||||
# First do world-level preprocessing. This scans the world hierarchy, reads
|
|
||||||
# in the region files and caches chunk modified times, and determines the
|
|
||||||
# chunk bounds (max and min in both dimensions)
|
|
||||||
w = world.World(worlddir)
|
|
||||||
rset = w.get_regionsets()[0] # use the default
|
|
||||||
if north_direction == 'auto':
|
|
||||||
# TODO get this from the asset manager # north_direction = w.persistentData['north_direction']
|
|
||||||
options.north_direction = north_direction
|
|
||||||
|
|
||||||
# TODO deal with changed north direction
|
|
||||||
|
|
||||||
# A couple other things we need to figure out about the world:
|
|
||||||
w.get_regionsets()[0].determine_bounds()
|
|
||||||
# w.find_true_spawn()
|
|
||||||
|
|
||||||
logging.info("Rendering the following tilesets: %s", ",".join(options.rendermode))
|
|
||||||
|
|
||||||
bgcolor = (int(options.bg_color[1:3],16),
|
|
||||||
int(options.bg_color[3:5],16),
|
|
||||||
int(options.bg_color[5:7],16),
|
|
||||||
0)
|
|
||||||
|
|
||||||
# Create the quadtrees. There is one quadtree per rendermode requested, and
|
|
||||||
# therefore, per output directory hierarchy of tiles. Each quadtree
|
|
||||||
# individually computes its depth and size. The constructor computes the
|
|
||||||
# depth of the tree, while the go() method re-arranges tiles if the current
|
|
||||||
# depth differs from the computed depth.
|
|
||||||
q = []
|
|
||||||
qtree_args = {'depth' : options.zoom,
|
|
||||||
'imgformat' : imgformat,
|
|
||||||
'imgquality' : options.imgquality,
|
|
||||||
'optimizeimg' : optimizeimg,
|
|
||||||
'bgcolor' : bgcolor,
|
|
||||||
'forcerender' : options.forcerender,
|
|
||||||
'rerender_prob' : options.stochastic_render
|
|
||||||
}
|
|
||||||
for rendermode in options.rendermode:
|
|
||||||
if rendermode == 'normal':
|
|
||||||
qtree = quadtree.QuadtreeGen(rset, destdir, rendermode=rendermode, tiledir='tiles', **qtree_args)
|
|
||||||
else:
|
|
||||||
qtree = quadtree.QuadtreeGen(rset, destdir, rendermode=rendermode, **qtree_args)
|
|
||||||
q.append(qtree)
|
|
||||||
|
|
||||||
# Make sure the quadtrees are the correct depth
|
|
||||||
for qtree in q:
|
|
||||||
qtree.check_depth()
|
|
||||||
|
|
||||||
# create the distributed render
|
|
||||||
r = rendernode.RenderNode(q, options)
|
|
||||||
# for the pool_initializer
|
|
||||||
r.builtin_custom_rendermodes = builtin_custom_rendermodes
|
|
||||||
|
|
||||||
# write out the map and web assets
|
|
||||||
m = googlemap.MapGen(q, configInfo=options)
|
|
||||||
m.go(options.procs)
|
|
||||||
|
|
||||||
# render the tiles!
|
|
||||||
r.go(options.procs)
|
|
||||||
|
|
||||||
# finish up the map
|
|
||||||
m.finalize()
|
|
||||||
|
|
||||||
if options.changelist:
|
|
||||||
changed=[]
|
|
||||||
for tile in r.rendered_tiles:
|
|
||||||
if options.changelist_format=="absolute":
|
|
||||||
tile=os.path.abspath(tile)
|
|
||||||
changed.append(tile)
|
|
||||||
for zl in range(q[0].p - 1):
|
|
||||||
tile=os.path.dirname(tile)
|
|
||||||
changed.append("%s.%s" % (tile, imgformat))
|
|
||||||
#Quick and nasty way to remove duplicate entries
|
|
||||||
changed=list(set(changed))
|
|
||||||
changed.sort()
|
|
||||||
for path in changed:
|
|
||||||
changefile.write("%s\n" % path)
|
|
||||||
changefile.close()
|
|
||||||
|
|
||||||
def list_rendermodes():
|
|
||||||
"Prints out a pretty list of supported rendermodes"
|
|
||||||
|
|
||||||
def print_mode_tree(line_max, mode, prefix='', last=False):
|
|
||||||
"Prints out a mode tree for the given mode, with an indent."
|
|
||||||
|
|
||||||
try:
|
|
||||||
info = c_overviewer.get_render_mode_info(mode)
|
|
||||||
except ValueError:
|
|
||||||
info = {}
|
|
||||||
|
|
||||||
print prefix + '+-', mode,
|
|
||||||
|
|
||||||
if 'description' in info:
|
|
||||||
print " " * (line_max - len(prefix) - len(mode) - 2),
|
|
||||||
print info['description']
|
|
||||||
else:
|
|
||||||
print
|
|
||||||
|
|
||||||
children = c_overviewer.get_render_mode_children(mode)
|
|
||||||
for child in children:
|
|
||||||
child_last = (child == children[-1])
|
|
||||||
if last:
|
|
||||||
child_prefix = ' '
|
|
||||||
else:
|
|
||||||
child_prefix = '| '
|
|
||||||
print_mode_tree(line_max, child, prefix=prefix + child_prefix, last=child_last)
|
|
||||||
|
|
||||||
avail_rendermodes = c_overviewer.get_render_modes()
|
|
||||||
line_lengths = {}
|
|
||||||
parent_modes = []
|
|
||||||
for mode in avail_rendermodes:
|
|
||||||
inherit = c_overviewer.get_render_mode_inheritance(mode)
|
|
||||||
if not inherit[0] in parent_modes:
|
|
||||||
parent_modes.append(inherit[0])
|
|
||||||
line_lengths[mode] = 2 * len(inherit) + 1 + len(mode)
|
|
||||||
|
|
||||||
line_length = max(line_lengths.values())
|
|
||||||
for mode in parent_modes:
|
|
||||||
print_mode_tree(line_length, mode, last=(mode == parent_modes[-1]))
|
|
||||||
|
|
||||||
def list_worlds():
|
def list_worlds():
|
||||||
"Prints out a brief summary of saves found in the default directory"
|
"Prints out a brief summary of saves found in the default directory"
|
||||||
@@ -582,18 +339,14 @@ def list_worlds():
|
|||||||
size = "%.2fMB" % (info['SizeOnDisk'] / 1024. / 1024.)
|
size = "%.2fMB" % (info['SizeOnDisk'] / 1024. / 1024.)
|
||||||
print formatString % (name, size, playstamp, timestamp)
|
print formatString % (name, size, playstamp, timestamp)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
multiprocessing.freeze_support()
|
multiprocessing.freeze_support()
|
||||||
try:
|
try:
|
||||||
main()
|
ret = main()
|
||||||
|
util.exit(ret)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
|
||||||
if e.args[0] == "Exiting":
|
|
||||||
logging.info("Exiting...")
|
|
||||||
doExit(code=0, wait=False)
|
|
||||||
logging.exception("""An error has occurred. This may be a bug. Please let us know!
|
logging.exception("""An error has occurred. This may be a bug. Please let us know!
|
||||||
See http://docs.overviewer.org/en/latest/index.html#help
|
See http://docs.overviewer.org/en/latest/index.html#help
|
||||||
|
|
||||||
This is the error that occurred:""")
|
This is the error that occurred:""")
|
||||||
doExit(code=1, consoleMsg=False)
|
util.exit(1)
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#
|
||||||
|
# Code to check to make sure c_overviewer is built and working
|
||||||
|
#
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import platform
|
||||||
|
import traceback
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import util
|
||||||
|
|
||||||
|
def check_c_overviewer():
|
||||||
|
"""Check to make sure c_overviewer works and is up-to-date. Prints
|
||||||
|
out a helpful error and returns 1 if something's wrong, returns 0
|
||||||
|
otherwise.
|
||||||
|
"""
|
||||||
|
root_dir = util.get_program_path()
|
||||||
|
# make sure the c_overviewer extension is available
|
||||||
|
try:
|
||||||
|
import c_overviewer
|
||||||
|
except ImportError:
|
||||||
|
## if this is a frozen windows package, the following error messages about
|
||||||
|
## building the c_overviewer extension are not appropriate
|
||||||
|
if hasattr(sys, "frozen") and platform.system() == 'Windows':
|
||||||
|
print "Something has gone wrong importing the c_overviewer extension. Please"
|
||||||
|
print "make sure the 2008 and 2010 redistributable packages from Microsoft"
|
||||||
|
print "are installed."
|
||||||
|
return 1
|
||||||
|
|
||||||
|
## try to find the build extension
|
||||||
|
ext = os.path.join(root_dir, "overviewer_core", "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
|
||||||
|
if os.path.exists(ext):
|
||||||
|
traceback.print_exc()
|
||||||
|
print ""
|
||||||
|
print "Something has gone wrong importing the c_overviewer extension. Please"
|
||||||
|
print "make sure it is up-to-date (clean and rebuild)"
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print "You need to compile the c_overviewer module to run Minecraft Overviewer."
|
||||||
|
print "Run `python setup.py build`, or see the README for details."
|
||||||
|
return 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# make sure it's up-to-date
|
||||||
|
#
|
||||||
|
|
||||||
|
if hasattr(sys, "frozen"):
|
||||||
|
pass # we don't bother with a compat test since it should always be in sync
|
||||||
|
elif "extension_version" in dir(c_overviewer):
|
||||||
|
# check to make sure the binary matches the headers
|
||||||
|
if os.path.exists(os.path.join(root_dir, "overviewer_core", "src", "overviewer.h")):
|
||||||
|
with open(os.path.join(root_dir, "overviewer_core", "src", "overviewer.h")) as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
|
||||||
|
if lines:
|
||||||
|
l = lines[0]
|
||||||
|
if int(l.split()[2].strip()) != c_overviewer.extension_version():
|
||||||
|
print "Please rebuild your c_overviewer module. It is out of date!"
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
print "Please rebuild your c_overviewer module. It is out of date!"
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# all good!
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# only check the module if we're not setup.py
|
||||||
|
if not sys.argv[0].endswith("setup.py"):
|
||||||
|
ret = check_c_overviewer()
|
||||||
|
if ret > 0:
|
||||||
|
util.exit(ret)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import imp
|
|||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
import platform
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
import logging
|
import logging
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
@@ -88,6 +89,33 @@ def findGitVersion():
|
|||||||
except Exception:
|
except Exception:
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
|
def is_bare_console():
|
||||||
|
"""Returns true if Overviewer is running in a bare console in
|
||||||
|
Windows, that is, if overviewer wasn't started in a cmd.exe
|
||||||
|
session.
|
||||||
|
"""
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
try:
|
||||||
|
import ctypes
|
||||||
|
GetConsoleProcessList = ctypes.windll.kernel32.GetConsoleProcessList
|
||||||
|
num = GetConsoleProcessList(ctypes.byref(ctypes.c_int(0)), ctypes.c_int(1))
|
||||||
|
if (num == 1):
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
def exit(ret=0):
|
||||||
|
"""Drop-in replacement for sys.exit that will automatically detect
|
||||||
|
bare consoles and wait for user input before closing.
|
||||||
|
"""
|
||||||
|
if ret and is_bare_console():
|
||||||
|
print
|
||||||
|
print "Press [Enter] to close this window."
|
||||||
|
raw_input()
|
||||||
|
sys.exit(ret)
|
||||||
|
|
||||||
# http://docs.python.org/library/itertools.html
|
# http://docs.python.org/library/itertools.html
|
||||||
def roundrobin(iterables):
|
def roundrobin(iterables):
|
||||||
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
|
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
|
||||||
|
|||||||
Reference in New Issue
Block a user