diff --git a/chunk.py b/chunk.py index 4ba13c8..0921e54 100644 --- a/chunk.py +++ b/chunk.py @@ -55,8 +55,7 @@ def get_lvldata(world, filename, x, y, retries=2): raise NoSuchChunk try: - d = world.load_from_region(filename, x, y) - #TODO should probably do rotation from here + d = world.load_from_region(filename, x, y) except Exception, e: if retries > 0: # wait a little bit, and try again (up to `retries` times) @@ -78,7 +77,7 @@ def get_blockarray(level, north_direction): def get_blockarray_fromfile(filename, north_direction): """Same as get_blockarray except takes a filename. This is a shortcut""" - d = nbt.load_from_region(filename, x, y) + d = nbt.load_from_region(filename, x, y, north_direction) level = d[1]['Level'] return get_blockarray(level, north_direction) diff --git a/nbt.py b/nbt.py index aa30700..7a095e8 100644 --- a/nbt.py +++ b/nbt.py @@ -17,6 +17,7 @@ import gzip, zlib import struct import StringIO import os +import numpy # decorator to handle filename or object as first parameter def _file_loader(func): @@ -34,15 +35,15 @@ def _file_loader(func): def load(fileobj): return NBTFileReader(fileobj).read_all() -def load_from_region(filename, x, y): - nbt = load_region(filename).load_chunk(x, y) +def load_from_region(filename, x, y, north_direction): + nbt = load_region(filename, north_direction).load_chunk(x, y) if nbt is None: return None ## return none. I think this is who we should indicate missing chunks #raise IOError("No such chunk in region: (%i, %i)" % (x, y)) return nbt.read_all() -def load_region(filename): - return MCRFileReader(filename) +def load_region(filename, north_direction): + return MCRFileReader(filename, north_direction) # compile the unpacker's into a classes @@ -199,13 +200,25 @@ class MCRFileReader(object): chunks (as instances of NBTFileReader), getting chunk timestamps, and for listing chunks contained in the file.""" - def __init__(self, filename): + def __init__(self, filename, north_direction): self._file = None self._filename = filename + self.north_direction = north_direction # cache used when the entire header tables are read in get_chunks() self._locations = None self._timestamps = None self._chunks = None + + def get_north_rotations(self): + #Upper-left and lower-right are swapped from chunk.py rots + if self.north_direction == "upper-left": + return 3 + elif self.north_direction == "upper-right": + return 2 + elif self.north_direction == "lower-right": + return 1 + elif self.north_direction == "lower-left": + return 0 def _read_24bit_int(self): """Read in a 24-bit, big-endian int, used in the chunk @@ -328,11 +341,13 @@ class MCRFileReader(object): locations_append = self._locations.append for _ in xrange(32*32): locations_append(self._read_chunk_location()) + self._locations = numpy.reshape(numpy.rot90(numpy.reshape(self._locations, (32,32)),self.get_north_rotations()), -1) # read chunk timestamp table timestamp_append = self._timestamps.append for _ in xrange(32*32): timestamp_append(self._read_chunk_timestamp()) + self._timestamps = numpy.reshape(numpy.rot90(numpy.reshape(self._timestamps, (32,32)),self.get_north_rotations()), -1) if closeFile: self.closefile() @@ -344,10 +359,10 @@ class MCRFileReader(object): load_chunk(), this will wrap x and y into the range [0, 31]. """ x = x % 32 - y = y % 32 + y = y % 32 if self._timestamps is None: self.get_chunk_info() - return self._timestamps[x + y * 32] + return self._timestamps[x + y * 32] def chunkExists(self, x, y): """Determines if a chunk exists without triggering loading of the backend data""" diff --git a/quadtree.py b/quadtree.py index 9ccb04f..fe5002f 100644 --- a/quadtree.py +++ b/quadtree.py @@ -240,10 +240,6 @@ class QuadtreeGen(object): continue chunkx, chunky = unconvert_coords(col, row) - if self.north_direction == 'upper-right': - chunky = -chunky - elif self.north_direction == 'lower-right': - chunkx = -chunkx regionx_ = chunkx//32 regiony_ = chunky//32 diff --git a/world.py b/world.py index abc995d..a53b823 100644 --- a/world.py +++ b/world.py @@ -169,7 +169,7 @@ class World(object): if self.regions.get(filename) is not None: self.regions[filename][0].closefile() chunkcache = {} - mcr = nbt.MCRFileReader(filename) + mcr = nbt.MCRFileReader(filename, self.north_direction) self.regions[filename] = (mcr,os.path.getmtime(filename),chunkcache) return mcr @@ -185,26 +185,12 @@ class World(object): in the image each one should be. Returns (col, row).""" # change this function, and you MUST change unconvert_coords - if self.north_direction == 'lower-left': - return (chunkx + chunky, chunky - chunkx) - elif self.north_direction == 'lower-right': - return (chunkx + chunky, chunkx - chunky) - elif self.north_direction == 'upper-left': - return (chunkx - chunky, chunkx + chunky) - elif self.north_direction == 'upper-right': - return (chunky - chunkx, chunkx + chunky) + return (chunkx + chunky, chunky - chunkx) def unconvert_coords(self, col, row): """Undoes what convert_coords does. Returns (chunkx, chunky).""" - if self.north_direction == 'lower-left': - return ((col - row) / 2, (row + col) / 2) - if self.north_direction == 'lower-right': - return ((col + row) / 2, (col - row) / 2) - if self.north_direction == 'upper-left': - return ((col + row) / 2, (row - col) / 2) - if self.north_direction == 'upper-right': - return ((row - col) / 2, (col + row) / 2) + return ((col - row) / 2, (row + col) / 2) def findTrueSpawn(self): """Adds the true spawn location to self.POI. The spawn Y coordinate @@ -225,7 +211,10 @@ class World(object): chunkFile = self.get_region_path(chunkX, chunkY) if chunkFile is not None: - data = nbt.load_from_region(chunkFile, chunkX, chunkY)[1] + #TODO I broke it + + #data = nbt.load_from_region(chunkFile, chunkX, chunkY, self.north_direction)[1] + data = None if data is not None: level = data['Level'] blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))