diff --git a/docs/faq.rst b/docs/faq.rst index 213d1d9..1fc9130 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -8,6 +8,36 @@ Frequently Asked Questions General Questions ================= +When my map expands, I see remnants of another zoom level +--------------------------------------------------------- + +When your map expands ("Your map seems to have expanded beyond its previous +bounds") you may see tiles at a zoom level that shouldn't be there, usually +around the borders. This is probably not a bug, but is typically caused by +copying the map tiles from their render destination to another location (such as +a web server). + +When you're copying the rendered map, you need to be sure files that *don't* +exist in the source are *deleted* in the destination. + +Explanation: When Overviewer re-arranges tiles to make room for another zoom +level, it moves some tiles tiles at a particular zoom level and places them at a +higher zoom level. The tiles that used to be at that zoom level should no longer +exist there, but if you're copying tiles, there is no mechanism to *delete* +those files at the copy destination. + +If that explanation doesn't make full sense, then just know that you must do one +of the following: + +* Render the tiles directly to the destination + +* Copy the tiles from the render destination in a way that deletes extra files, + such as using ``rsync`` with ``--delete`` + +* Erase and re-copy the files at the final destination when the map expands. + Map expansions double the width and height of the map, so you will eventually + hit a map size that is unlikely to need another level. + The full map doesn't display even when fully zoomed out! -------------------------------------------------------- @@ -16,11 +46,13 @@ commandline or in settings.py? If so, try removing it, or increasing the value you set. It's quite likely you don't need it at all. See the documentation for the :option:`zoom <-z>` option. -You've added a few feature, but it's not showing up on my map! --------------------------------------------------------------- +You've added a few feature or changed textures, but it's not showing up on my map! +---------------------------------------------------------------------------------- Some new features will only show up in newly-rendered areas. Use the -:option:`--forcerender` option to update the entire map. +:option:`--forcerender` option to update the entire map. If you have a really +large map and don't want to re-render everything, take a look at +the :option:`--stochastic-render` option. How do I use this on CentOS 5? ------------------------------ diff --git a/docs/index.rst b/docs/index.rst index b471a14..d2c717c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -50,7 +50,7 @@ Requirements This is a quick list of what's required to run The Overviewer. It runs on Windows, Mac, and Linux as long as you have these software packages installed: -* Python 2.6 or 2.7 +* Python 2.6 or 2.7 (we are *not* yet compatible with Python 3.x) * PIL (Python Imaging Library) @@ -86,7 +86,10 @@ Help **IF YOU NEED HELP COMPILING OR RUNNING THE OVERVIEWER** feel free to chat with us live in IRC: #overviewer on Freenode. There's usually someone on there that can help you out. Not familiar with IRC? `Use the web client -`_. +`_. (If there's no immediate +response, wait around or try a different time of day; we have to sleep sometime) + +Also check our :doc:`Frequently Asked Questions ` page. If you think you've found a bug or other issue, file an issue on our `Issue Tracker `_. Filing or diff --git a/overviewer.py b/overviewer.py index 0e3c3c9..3f618ed 100755 --- a/overviewer.py +++ b/overviewer.py @@ -18,28 +18,25 @@ import platform import sys +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" + if sys.version_info[0] >= 3: + print "and will not run on Python 3.0 or later" + 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): - 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(1) + isBareConsole = True except Exception: pass -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" - if sys.version_info[0] >= 3: - print "and will not run on Python 3.0 or later" - sys.exit(1) - import os import os.path import re @@ -49,6 +46,35 @@ import time 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 @@ -61,7 +87,7 @@ except ImportError: 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." - sys.exit(1) + doExit() ## try to find the build extension @@ -69,7 +95,7 @@ except ImportError: 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)" - sys.exit(1) + doExit() import traceback traceback.print_exc() @@ -77,7 +103,7 @@ except ImportError: 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." - sys.exit(1) + doExit() from overviewer_core import textures @@ -93,10 +119,10 @@ elif "extension_version" in dir(c_overviewer): 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!" - sys.exit(1) + doExit(code=1, consoleMsg=True) else: print "Please rebuild your c_overviewer module. It is out of date!" - sys.exit(1) + doExit() from overviewer_core.configParser import ConfigOptionParser from overviewer_core import optimizeimages, world, quadtree @@ -225,7 +251,7 @@ def main(): except Exception: print "version info not found" pass - sys.exit(0) + doExit(code=0, consoleMsg=False) # setup c_overviewer rendermode customs / options for mode in builtin_custom_rendermodes: @@ -245,7 +271,7 @@ def main(): if options.list_rendermodes: list_rendermodes() - sys.exit(0) + doExit(code=0, consoleMsg=False) if options.check_terrain: import hashlib @@ -257,22 +283,22 @@ def main(): f = _find_file("terrain.png", verbose=True) except IOError: logging.error("Could not find the file terrain.png") - sys.exit(1) + doExit(code=1, consoleMsg=False) h = hashlib.sha1() h.update(f.read()) logging.info("Hash of terrain.png file is: `%s`", h.hexdigest()) - sys.exit(0) + doExit(code=0, consoleMsg=False) if options.advanced_help: parser.advanced_help() - sys.exit(0) + doExit(code=0, consoleMsg=False) if len(args) < 1: logging.error("You need to give me your world number or directory") parser.print_help() list_worlds() - sys.exit(1) + doExit(code=1, consoleMsg=True) worlddir = os.path.expanduser(args[0]) if len(args) > 2: @@ -284,7 +310,7 @@ def main(): 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\ dir but you forgot to put quotes around the directory, since it contains spaces." % " ".join(args[start:end])) - sys.exit(1) + doExit(code=1, consoleMsg=False) if not os.path.exists(worlddir): # world given is either world number, or name @@ -294,7 +320,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces. if not worlds: parser.print_help() logging.error("Invalid world path") - sys.exit(1) + doExit(code=1, consoleMsg=False) try: worldnum = int(worlddir) @@ -307,32 +333,32 @@ dir but you forgot to put quotes around the directory, since it contains spaces. # it's not a number, name, or path parser.print_help() logging.error("Invalid world name or path") - sys.exit(1) + doExit(code=1, consoleMsg=False) except KeyError: # it was an invalid number parser.print_help() logging.error("Invalid world number") - sys.exit(1) + doExit(code=1, consoleMsg=False) # final sanity check for worlddir if not os.path.exists(os.path.join(worlddir, 'level.dat')): logging.error("Invalid world path -- does not contain level.dat") - sys.exit(1) + doExit(code=1, consoleMsg=False) if len(args) < 2: logging.error("Where do you want to save the tiles?") - sys.exit(1) + doExit(code=1, consoleMsg=False) elif len(args) > 2: parser.print_help() logging.error("Sorry, you specified too many arguments") - sys.exit(1) + doExit(code=1, consoleMsg=False) destdir = os.path.expanduser(args[1]) if options.display_config: # just display the config file and exit parser.display_config() - sys.exit(0) + doExit(code=0, consoleMsg=False) if options.regionlist: @@ -365,11 +391,11 @@ dir but you forgot to put quotes around the directory, since it contains spaces. except IOError as e: logging.error("Unable to open file %s to use for changelist." % options.changelist) logging.error("I/O Error: %s" % e.strerror) - sys.exit(1) + doExit(code=1, consoleMsg=False) if options.changelist_format != "auto" and not options.changelist: logging.error("changelist_format specified without changelist.") - sys.exit(1) + doExit(code=1, consoleMsg=False) if options.changelist_format == "auto": options.changelist_format = "relative" @@ -385,7 +411,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces. textures.generate(path=options.textures_path) except IOError, e: logging.error(str(e)) - sys.exit(1) + doExit(code=1, consoleMsg=False) # First do world-level preprocessing. This scans the world hierarchy, reads # in the region files and caches chunk modified times, and determines the @@ -402,7 +428,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces. logging.error("Overviewer.dat gives previous north-direction as "+w.persistentData['north_direction']) logging.error("Requested north-direction was "+north_direction) logging.error("To change north-direction of an existing render, use --forcerender") - sys.exit(1) + doExit(code=1, consoleMsg=False) # A couple other things we need to figure out about the world: w.determine_bounds() @@ -549,8 +575,9 @@ if __name__ == "__main__": except Exception, e: if e.message == "Exiting": logging.info("Exiting...") - sys.exit(0) + doExit(code=0, wait=False) 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 This is the error that occurred:""") + doExit(code=1, consoleMsg=False) diff --git a/overviewer_core/quadtree.py b/overviewer_core/quadtree.py index 01b1536..200f998 100644 --- a/overviewer_core/quadtree.py +++ b/overviewer_core/quadtree.py @@ -214,7 +214,7 @@ class QuadtreeGen(object): curdepth = self._get_cur_depth() if curdepth != -1: if self.p > curdepth: - logging.warning("Your map seemes to have expanded beyond its previous bounds.") + logging.warning("Your map seems to have expanded beyond its previous bounds.") logging.warning( "Doing some tile re-arrangements... just a sec...") for _ in xrange(self.p-curdepth): self._increase_depth() diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index 0fc1109..adc790d 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -47,7 +47,7 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) { if ((!textures)) { return NULL; } - + chunk_mod = PyImport_ImportModule("overviewer_core.chunk"); /* ensure none of these pointers are NULL */ if ((!chunk_mod)) { @@ -62,10 +62,13 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) { if (!tmp) return NULL; max_blockid = PyInt_AsLong(tmp); + Py_DECREF(tmp); + tmp = PyObject_GetAttrString(textures, "max_data"); if (!tmp) return NULL; max_data = PyInt_AsLong(tmp); + Py_DECREF(tmp); /* assemble the property table */ known_blocks = PyObject_GetAttrString(textures, "known_blocks"); @@ -101,7 +104,7 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) { Py_DECREF(block); } - + Py_RETURN_NONE; } @@ -370,7 +373,8 @@ chunk_render(PyObject *self, PyObject *args) { state.rendermode = rendermode = render_mode_create(PyString_AsString(rendermode_py), &state); Py_DECREF(rendermode_py); if (rendermode == NULL) { - return NULL; + return NULL; // note that render_mode_create will + // set PyErr. No need to set it here } /* get the image size */ diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c index dd0848f..fb523fb 100644 --- a/overviewer_core/src/rendermodes.c +++ b/overviewer_core/src/rendermodes.c @@ -106,13 +106,13 @@ render_mode_find_interface(const char *mode) { /* check for custom modes */ custom = PyDict_GetItemString(custom_render_modes, mode); if (custom == NULL) - return NULL; + return PyErr_Format(PyExc_RuntimeError, "Failed to find rendermode interface (custom not found)"); custom = PyDict_GetItemString(custom, "parent"); if (custom == NULL) - return NULL; + return PyErr_Format(PyExc_RuntimeError, "Failed to find rendermode interface (parent not found)"); custom_parent = PyString_AsString(custom); if (custom_parent == NULL) - return NULL; + return NULL; // PyString_AsString sets an exception return render_mode_find_interface(custom_parent); } @@ -133,14 +133,14 @@ RenderMode *render_mode_create(const char *mode, RenderState *state) { ret = calloc(1, sizeof(RenderMode)); if (ret == NULL) { Py_DECREF(options); - return NULL; + return PyErr_Format(PyExc_RuntimeError, "Failed to alloc a rendermode"); } ret->mode = calloc(1, iface->data_size); if (ret->mode == NULL) { Py_DECREF(options); free(ret); - return NULL; + return PyErr_Format(PyExc_RuntimeError, "Failed to alloc rendermode data"); } ret->iface = iface; @@ -156,7 +156,7 @@ RenderMode *render_mode_create(const char *mode, RenderState *state) { Py_DECREF(options); return ret; } - + void render_mode_destroy(RenderMode *self) { self->iface->finish(self->mode, self->state); free(self->mode);