0

Generalized regionset wrapper objects so they can be chained

This commit is contained in:
Andrew Brown
2012-02-26 17:59:37 -05:00
parent 4f0e844bb5
commit e50cb2db88
2 changed files with 54 additions and 27 deletions

View File

@@ -365,8 +365,11 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
if rset == None: # indicates no such dimension was found:
logging.error("Sorry, you requested dimension '%s' for %s, but I couldn't find it", render['dimension'], render_name)
return 1
# If this is to be a rotated regionset, wrap it in a RotatedRegionSet
# object
if (render['northdirection'] > 0):
rset = rset.rotate(render['northdirection'])
rset = world.RotatedRegionSet(rset, render['northdirection'])
logging.debug("Using RegionSet %r", rset)
# create our TileSet from this RegionSet

View File

@@ -36,10 +36,10 @@ class BiomeDataDoesntExist(Exception):
pass
def log_other_exceptions(func):
"""A decorator that prints out any errors that are not
ChunkDoesntExist or BiomeDataDoesntExist errors. This decorates
get_chunk because the C code is likely to swallow exceptions, so
this will at least make them visible.
"""A decorator that prints out any errors that are not ChunkDoesntExist or
BiomeDataDoesntExist errors. This should decorate any functions or methods
called by the C code, such as get_chunk(), because the C code is likely to
swallow exceptions. This will at least make them visible.
"""
functools.wraps(func)
@@ -265,7 +265,6 @@ class RegionSet(object):
raise Exception("Woah, what kind of dimension is this! %r" % self.regiondir)
# this is decorated with cache.lru_cache in __init__(). Be aware!
@log_other_exceptions
def _get_biome_data_for_region(self, regionx, regionz):
"""Get the block of biome data for an entire region. Biome
data is in the format output by Minecraft Biome Extractor:
@@ -366,9 +365,6 @@ class RegionSet(object):
return chunk_data
def rotate(self, north_direction):
return RotatedRegionSet(self.regiondir, north_direction)
def iterate_chunks(self):
"""Returns an iterator over all chunk metadata in this world. Iterates
over tuples of integers (x,z,mtime) for each chunk. Other chunk data
@@ -420,6 +416,33 @@ class RegionSet(object):
y = int(p[2])
yield (x, y, path)
class RegionSetWrapper(object):
"""This is the base class for all "wrappers" of RegionSet objects. A
wrapper is an object that acts similarly to a subclass: some methods are
overridden and functionality is changed, others may not be. The difference
here is that these wrappers may wrap each other, forming chains.
In fact, subclasses of this object may act exactly as if they've subclassed
the original RegionSet object, except the first parameter of the
constructor is a regionset object, not a regiondir.
This class must implement the full public interface of RegionSet objects
"""
def __init__(self, rsetobj):
self._r = rsetobj
def get_type(self):
return self._r.get_type()
def get_biome_data(self, x, z):
return self._r.get_biome_data(x,z)
def get_chunk(self, x, z):
return self._r.get_chunk(x,z)
def iterate_chunks(self):
return self._r.iterate_chunks()
def get_chunk_mtime(self, x, z):
return self._r.get_chunk_mtime(x,z)
# see RegionSet.rotate. These values are chosen so that they can be
# passed directly to rot90; this means that they're the number of
# times to rotate by 90 degrees CCW
@@ -428,7 +451,7 @@ UPPER_RIGHT = 1 ## - Return the world such that north is down the +X axis (rotat
LOWER_RIGHT = 2 ## - Return the world such that north is down the +Z axis (rotate 180 degrees)
LOWER_LEFT = 3 ## - Return the world such that north is down the -X axis (rotate 90 degrees clockwise)
class RotatedRegionSet(RegionSet):
class RotatedRegionSet(RegionSetWrapper):
"""A regionset, only rotated such that north points in the given direction
"""
@@ -440,32 +463,33 @@ class RotatedRegionSet(RegionSet):
_ROTATE_180 = lambda x,z: (-x,-z)
# These take rotated coords and translate into un-rotated coords
_unrotation_funcs = {
0: _NO_ROTATION,
1: _ROTATE_COUNTERCLOCKWISE,
2: _ROTATE_180,
3: _ROTATE_CLOCKWISE,
}
_unrotation_funcs = [
_NO_ROTATION,
_ROTATE_COUNTERCLOCKWISE,
_ROTATE_180,
_ROTATE_CLOCKWISE,
]
# These translate un-rotated coordinates into rotated coordinates
_rotation_funcs = {
0: _NO_ROTATION,
1: _ROTATE_CLOCKWISE,
2: _ROTATE_180,
3: _ROTATE_COUNTERCLOCKWISE,
}
_rotation_funcs = [
_NO_ROTATION,
_ROTATE_CLOCKWISE,
_ROTATE_180,
_ROTATE_COUNTERCLOCKWISE,
]
def __init__(self, regiondir, north_dir):
def __init__(self, rsetobj, north_dir):
self.north_dir = north_dir
self.unrotate = self._unrotation_funcs[north_dir]
self.rotate = self._rotation_funcs[north_dir]
super(RotatedRegionSet, self).__init__(regiondir)
super(RotatedRegionSet, self).__init__(rsetobj)
# Re-initialize upon unpickling
# Re-initialize upon unpickling. This is needed because we store a couple
# lambda functions as instance variables
def __getstate__(self):
return (self.regiondir, self.north_dir)
return (self._r, self.north_dir)
def __setstate__(self, args):
self.__init__(args[0], args[1])
@@ -476,7 +500,7 @@ class RotatedRegionSet(RegionSet):
def get_chunk(self, x, z):
x,z = self.unrotate(x,z)
chunk_data = super(RotatedRegionSet, self).get_chunk(x,z)
chunk_data = dict(super(RotatedRegionSet, self).get_chunk(x,z))
chunk_data['Blocks'] = numpy.rot90(chunk_data['Blocks'], self.north_dir)
chunk_data['Data'] = numpy.rot90(chunk_data['Data'], self.north_dir)
chunk_data['SkyLight'] = numpy.rot90(chunk_data['SkyLight'], self.north_dir)