0

Merge remote-tracking branch 'origin/master' into brownan-chunkscan

Conflicts:
	overviewer.py
This commit is contained in:
Andrew Brown
2011-11-26 16:58:27 -05:00
6 changed files with 117 additions and 51 deletions

View File

@@ -8,6 +8,36 @@ Frequently Asked Questions
General 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! 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 you set. It's quite likely you don't need it at all. See the documentation for
the :option:`zoom <-z>` option. 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 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? How do I use this on CentOS 5?
------------------------------ ------------------------------

View File

@@ -50,7 +50,7 @@ Requirements
This is a quick list of what's required to run The Overviewer. It runs on 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: 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) * PIL (Python Imaging Library)
@@ -86,7 +86,10 @@ Help
**IF YOU NEED HELP COMPILING OR RUNNING THE OVERVIEWER** feel free to chat with **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 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 can help you out. Not familiar with IRC? `Use the web client
<http://webchat.freenode.net/?channels=overviewer>`_. <http://webchat.freenode.net/?channels=overviewer>`_. (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 <faq>` page.
If you think you've found a bug or other issue, file an issue on our `Issue If you think you've found a bug or other issue, file an issue on our `Issue
Tracker <https://github.com/overviewer/Minecraft-Overviewer/issues>`_. Filing or Tracker <https://github.com/overviewer/Minecraft-Overviewer/issues>`_. Filing or

View File

@@ -18,28 +18,25 @@
import platform import platform
import sys 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': if platform.system() == 'Windows':
try: try:
import ctypes import ctypes
GetConsoleProcessList = ctypes.windll.kernel32.GetConsoleProcessList GetConsoleProcessList = ctypes.windll.kernel32.GetConsoleProcessList
num = GetConsoleProcessList(ctypes.byref(ctypes.c_int(0)), ctypes.c_int(1)) num = GetConsoleProcessList(ctypes.byref(ctypes.c_int(0)), ctypes.c_int(1))
if (num == 1): if (num == 1):
print "The Overviewer is a console program. Please open a Windows command prompt" isBareConsole = True
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)
except Exception: except Exception:
pass 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
import os.path import os.path
import re import re
@@ -49,6 +46,35 @@ import time
import logging import logging
from overviewer_core import util 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() this_dir = util.get_program_path()
# make sure the c_overviewer extension is available # 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 "Something has gone wrong importing the c_overviewer extension. Please"
print "make sure the 2008 and 2010 redistributable packages from Microsoft" print "make sure the 2008 and 2010 redistributable packages from Microsoft"
print "are installed." print "are installed."
sys.exit(1) doExit()
## try to find the build extension ## try to find the build extension
@@ -69,7 +95,7 @@ except ImportError:
if os.path.exists(ext): if os.path.exists(ext):
print "Something has gone wrong importing the c_overviewer extension. Please" print "Something has gone wrong importing the c_overviewer extension. Please"
print "make sure it is up-to-date (clean and rebuild)" print "make sure it is up-to-date (clean and rebuild)"
sys.exit(1) doExit()
import traceback import traceback
traceback.print_exc() traceback.print_exc()
@@ -77,7 +103,7 @@ except ImportError:
print "" print ""
print "You need to compile the c_overviewer module to run Minecraft Overviewer." 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." print "Run `python setup.py build`, or see the README for details."
sys.exit(1) doExit()
from overviewer_core import textures from overviewer_core import textures
@@ -93,10 +119,10 @@ elif "extension_version" in dir(c_overviewer):
l = lines[0] l = lines[0]
if int(l.split()[2].strip()) != c_overviewer.extension_version(): if int(l.split()[2].strip()) != c_overviewer.extension_version():
print "Please rebuild your c_overviewer module. It is out of date!" print "Please rebuild your c_overviewer module. It is out of date!"
sys.exit(1) doExit(code=1, consoleMsg=True)
else: else:
print "Please rebuild your c_overviewer module. It is out of date!" 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.configParser import ConfigOptionParser
from overviewer_core import optimizeimages, world, quadtree from overviewer_core import optimizeimages, world, quadtree
@@ -225,7 +251,7 @@ def main():
except Exception: except Exception:
print "version info not found" print "version info not found"
pass pass
sys.exit(0) doExit(code=0, consoleMsg=False)
# setup c_overviewer rendermode customs / options # setup c_overviewer rendermode customs / options
for mode in builtin_custom_rendermodes: for mode in builtin_custom_rendermodes:
@@ -245,7 +271,7 @@ def main():
if options.list_rendermodes: if options.list_rendermodes:
list_rendermodes() list_rendermodes()
sys.exit(0) doExit(code=0, consoleMsg=False)
if options.check_terrain: if options.check_terrain:
import hashlib import hashlib
@@ -257,22 +283,22 @@ def main():
f = _find_file("terrain.png", verbose=True) f = _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")
sys.exit(1) doExit(code=1, consoleMsg=False)
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())
sys.exit(0) doExit(code=0, consoleMsg=False)
if options.advanced_help: if options.advanced_help:
parser.advanced_help() parser.advanced_help()
sys.exit(0) doExit(code=0, consoleMsg=False)
if len(args) < 1: if len(args) < 1:
logging.error("You need to give me your world number or directory") logging.error("You need to give me your world number or directory")
parser.print_help() parser.print_help()
list_worlds() list_worlds()
sys.exit(1) doExit(code=1, consoleMsg=True)
worlddir = os.path.expanduser(args[0]) worlddir = os.path.expanduser(args[0])
if len(args) > 2: if len(args) > 2:
@@ -284,7 +310,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]))
sys.exit(1) doExit(code=1, consoleMsg=False)
if not os.path.exists(worlddir): if not os.path.exists(worlddir):
# world given is either world number, or name # 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: if not worlds:
parser.print_help() parser.print_help()
logging.error("Invalid world path") logging.error("Invalid world path")
sys.exit(1) doExit(code=1, consoleMsg=False)
try: try:
worldnum = int(worlddir) 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 # it's not a number, name, or path
parser.print_help() parser.print_help()
logging.error("Invalid world name or path") logging.error("Invalid world name or path")
sys.exit(1) doExit(code=1, consoleMsg=False)
except KeyError: except KeyError:
# it was an invalid number # it was an invalid number
parser.print_help() parser.print_help()
logging.error("Invalid world number") logging.error("Invalid world number")
sys.exit(1) doExit(code=1, consoleMsg=False)
# final sanity check for worlddir # final sanity check for worlddir
if not os.path.exists(os.path.join(worlddir, 'level.dat')): if not os.path.exists(os.path.join(worlddir, 'level.dat')):
logging.error("Invalid world path -- does not contain level.dat") logging.error("Invalid world path -- does not contain level.dat")
sys.exit(1) doExit(code=1, consoleMsg=False)
if len(args) < 2: if len(args) < 2:
logging.error("Where do you want to save the tiles?") logging.error("Where do you want to save the tiles?")
sys.exit(1) doExit(code=1, consoleMsg=False)
elif len(args) > 2: elif len(args) > 2:
parser.print_help() parser.print_help()
logging.error("Sorry, you specified too many arguments") logging.error("Sorry, you specified too many arguments")
sys.exit(1) doExit(code=1, consoleMsg=False)
destdir = os.path.expanduser(args[1]) destdir = os.path.expanduser(args[1])
if options.display_config: if options.display_config:
# just display the config file and exit # just display the config file and exit
parser.display_config() parser.display_config()
sys.exit(0) doExit(code=0, consoleMsg=False)
if options.regionlist: 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: 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)
sys.exit(1) doExit(code=1, consoleMsg=False)
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.")
sys.exit(1) doExit(code=1, consoleMsg=False)
if options.changelist_format == "auto": if options.changelist_format == "auto":
options.changelist_format = "relative" 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) textures.generate(path=options.textures_path)
except IOError, e: except IOError, e:
logging.error(str(e)) logging.error(str(e))
sys.exit(1) doExit(code=1, consoleMsg=False)
# First do world-level preprocessing. This scans the world hierarchy, reads # First do world-level preprocessing. This scans the world hierarchy, reads
# in the region files and caches chunk modified times, and determines the # 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("Overviewer.dat gives previous north-direction as "+w.persistentData['north_direction'])
logging.error("Requested north-direction was "+north_direction) logging.error("Requested north-direction was "+north_direction)
logging.error("To change north-direction of an existing render, use --forcerender") 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: # A couple other things we need to figure out about the world:
w.determine_bounds() w.determine_bounds()
@@ -549,8 +575,9 @@ if __name__ == "__main__":
except Exception, e: except Exception, e:
if e.message == "Exiting": if e.message == "Exiting":
logging.info("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! 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)

View File

@@ -214,7 +214,7 @@ class QuadtreeGen(object):
curdepth = self._get_cur_depth() curdepth = self._get_cur_depth()
if curdepth != -1: if curdepth != -1:
if self.p > curdepth: 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...") logging.warning( "Doing some tile re-arrangements... just a sec...")
for _ in xrange(self.p-curdepth): for _ in xrange(self.p-curdepth):
self._increase_depth() self._increase_depth()

View File

@@ -47,7 +47,7 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) {
if ((!textures)) { if ((!textures)) {
return NULL; return NULL;
} }
chunk_mod = PyImport_ImportModule("overviewer_core.chunk"); chunk_mod = PyImport_ImportModule("overviewer_core.chunk");
/* ensure none of these pointers are NULL */ /* ensure none of these pointers are NULL */
if ((!chunk_mod)) { if ((!chunk_mod)) {
@@ -62,10 +62,13 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) {
if (!tmp) if (!tmp)
return NULL; return NULL;
max_blockid = PyInt_AsLong(tmp); max_blockid = PyInt_AsLong(tmp);
Py_DECREF(tmp);
tmp = PyObject_GetAttrString(textures, "max_data"); tmp = PyObject_GetAttrString(textures, "max_data");
if (!tmp) if (!tmp)
return NULL; return NULL;
max_data = PyInt_AsLong(tmp); max_data = PyInt_AsLong(tmp);
Py_DECREF(tmp);
/* assemble the property table */ /* assemble the property table */
known_blocks = PyObject_GetAttrString(textures, "known_blocks"); known_blocks = PyObject_GetAttrString(textures, "known_blocks");
@@ -101,7 +104,7 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) {
Py_DECREF(block); Py_DECREF(block);
} }
Py_RETURN_NONE; Py_RETURN_NONE;
} }
@@ -370,7 +373,8 @@ chunk_render(PyObject *self, PyObject *args) {
state.rendermode = rendermode = render_mode_create(PyString_AsString(rendermode_py), &state); state.rendermode = rendermode = render_mode_create(PyString_AsString(rendermode_py), &state);
Py_DECREF(rendermode_py); Py_DECREF(rendermode_py);
if (rendermode == NULL) { 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 */ /* get the image size */

View File

@@ -106,13 +106,13 @@ render_mode_find_interface(const char *mode) {
/* check for custom modes */ /* check for custom modes */
custom = PyDict_GetItemString(custom_render_modes, mode); custom = PyDict_GetItemString(custom_render_modes, mode);
if (custom == NULL) if (custom == NULL)
return NULL; return PyErr_Format(PyExc_RuntimeError, "Failed to find rendermode interface (custom not found)");
custom = PyDict_GetItemString(custom, "parent"); custom = PyDict_GetItemString(custom, "parent");
if (custom == NULL) if (custom == NULL)
return NULL; return PyErr_Format(PyExc_RuntimeError, "Failed to find rendermode interface (parent not found)");
custom_parent = PyString_AsString(custom); custom_parent = PyString_AsString(custom);
if (custom_parent == NULL) if (custom_parent == NULL)
return NULL; return NULL; // PyString_AsString sets an exception
return render_mode_find_interface(custom_parent); 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)); ret = calloc(1, sizeof(RenderMode));
if (ret == NULL) { if (ret == NULL) {
Py_DECREF(options); Py_DECREF(options);
return NULL; return PyErr_Format(PyExc_RuntimeError, "Failed to alloc a rendermode");
} }
ret->mode = calloc(1, iface->data_size); ret->mode = calloc(1, iface->data_size);
if (ret->mode == NULL) { if (ret->mode == NULL) {
Py_DECREF(options); Py_DECREF(options);
free(ret); free(ret);
return NULL; return PyErr_Format(PyExc_RuntimeError, "Failed to alloc rendermode data");
} }
ret->iface = iface; ret->iface = iface;
@@ -156,7 +156,7 @@ RenderMode *render_mode_create(const char *mode, RenderState *state) {
Py_DECREF(options); Py_DECREF(options);
return ret; return ret;
} }
void render_mode_destroy(RenderMode *self) { void render_mode_destroy(RenderMode *self) {
self->iface->finish(self->mode, self->state); self->iface->finish(self->mode, self->state);
free(self->mode); free(self->mode);