Merge remote branch 'rmrector/configurable-north' into configurable-north
Conflicts: overviewer.py overviewer_core/world.py
This commit is contained in:
@@ -195,6 +195,10 @@ Options
|
||||
--list-rendermodes
|
||||
List the available render modes, and a short description of each.
|
||||
|
||||
--north-direction=NORTH_DIRECTION
|
||||
Specifies which corner of the screen north will point to.
|
||||
Valid options are: lower-left, upper-left, upper-right, lower-right.
|
||||
|
||||
--settings=PATH
|
||||
Use this option to load settings from a file. The format of this file is
|
||||
given below.
|
||||
@@ -264,6 +268,10 @@ textures_path
|
||||
source. Overviewer looks in here for terrain.png and other textures before
|
||||
it looks anywhere else.
|
||||
|
||||
north_direction
|
||||
Specifies which corner of the screen north will point to.
|
||||
Valid options are: lower-left, upper-left, upper-right, lower-right.
|
||||
|
||||
Viewing the Results
|
||||
-------------------
|
||||
Within the output directory you will find two things: an index.html file, and a
|
||||
|
||||
@@ -96,6 +96,7 @@ def main():
|
||||
cpus = 1
|
||||
|
||||
avail_rendermodes = c_overviewer.get_render_modes()
|
||||
avail_north_dirs = ['lower-left', 'upper-left', 'upper-right', 'lower-right']
|
||||
|
||||
parser = ConfigOptionParser(usage=helptext, config="settings.py")
|
||||
parser.add_option("-V", "--version", dest="version", helptext="Displays version information and then exits", action="store_true")
|
||||
@@ -116,6 +117,7 @@ def main():
|
||||
parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0, helptext="Print more output. You can specify this option multiple times.")
|
||||
parser.add_option("--skip-js", dest="skipjs", action="store_true", helptext="Don't output marker.js or regions.js")
|
||||
parser.add_option("--no-signs", dest="nosigns", action="store_true", helptext="Don't output signs to markers.js")
|
||||
parser.add_option("--north-direction", dest="north_direction", helptext="Specifies which corner of the screen north will point to. Valid options are: " + ", ".join(avail_north_dirs) + ".", type="choice", default=avail_north_dirs[0], choices=avail_north_dirs)
|
||||
parser.add_option("--display-config", dest="display_config", action="store_true", helptext="Display the configuration parameters, but don't render the map. Requires all required options to be specified", commandLineOnly=True)
|
||||
#parser.add_option("--write-config", dest="write_config", action="store_true", helptext="Writes out a sample config file", commandLineOnly=True)
|
||||
|
||||
@@ -220,6 +222,11 @@ def main():
|
||||
else:
|
||||
optimizeimg = None
|
||||
|
||||
if options.north_direction:
|
||||
north_direction = options.north_direction
|
||||
else:
|
||||
north_direction = 'lower-left'
|
||||
|
||||
logging.getLogger().setLevel(
|
||||
logging.getLogger().level + 10*options.quiet)
|
||||
logging.getLogger().setLevel(
|
||||
@@ -233,7 +240,7 @@ def main():
|
||||
logging.info("Notice: Not using biome data for tinting")
|
||||
|
||||
# First do world-level preprocessing
|
||||
w = world.World(worlddir, destdir, useBiomeData=useBiomeData, regionlist=regionlist)
|
||||
w = world.World(worlddir, destdir, useBiomeData=useBiomeData, regionlist=regionlist, north_direction=north_direction)
|
||||
w.go(options.procs)
|
||||
|
||||
logging.info("Rending the following tilesets: %s", ",".join(options.rendermode))
|
||||
|
||||
@@ -73,18 +73,30 @@ def get_lvldata(world, filename, x, y, retries=2):
|
||||
def get_blockarray(level):
|
||||
"""Takes the level struct as returned from get_lvldata, and returns the
|
||||
Block array, which just contains all the block ids"""
|
||||
return numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
||||
return level['Blocks']
|
||||
|
||||
def get_blockarray_fromfile(filename):
|
||||
def get_blockarray_fromfile(filename, north_direction='lower-left'):
|
||||
"""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)
|
||||
chunk_data = level
|
||||
rots = 0
|
||||
if self.north_direction == 'upper-left':
|
||||
rots = 1
|
||||
elif self.north_direction == 'upper-right':
|
||||
rots = 2
|
||||
elif self.north_direction == 'lower-right':
|
||||
rots = 3
|
||||
|
||||
chunk_data['Blocks'] = numpy.rot90(numpy.frombuffer(
|
||||
level['Blocks'], dtype=numpy.uint8).reshape((16,16,128)),
|
||||
rots)
|
||||
return get_blockarray(chunk_data)
|
||||
|
||||
def get_skylight_array(level):
|
||||
"""Returns the skylight array. This is 4 bits per block, but it is
|
||||
expanded for you so you may index it normally."""
|
||||
skylight = numpy.frombuffer(level['SkyLight'], dtype=numpy.uint8).reshape((16,16,64))
|
||||
skylight = level['SkyLight']
|
||||
# this array is 2 blocks per byte, so expand it
|
||||
skylight_expanded = numpy.empty((16,16,128), dtype=numpy.uint8)
|
||||
# Even elements get the lower 4 bits
|
||||
@@ -97,7 +109,7 @@ def get_blocklight_array(level):
|
||||
"""Returns the blocklight array. This is 4 bits per block, but it
|
||||
is expanded for you so you may index it normally."""
|
||||
# expand just like get_skylight_array()
|
||||
blocklight = numpy.frombuffer(level['BlockLight'], dtype=numpy.uint8).reshape((16,16,64))
|
||||
blocklight = level['BlockLight']
|
||||
blocklight_expanded = numpy.empty((16,16,128), dtype=numpy.uint8)
|
||||
blocklight_expanded[:,:,::2] = blocklight & 0x0F
|
||||
blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4
|
||||
@@ -106,7 +118,7 @@ def get_blocklight_array(level):
|
||||
def get_blockdata_array(level):
|
||||
"""Returns the ancillary data from the 'Data' byte array. Data is packed
|
||||
in a similar manner to skylight data"""
|
||||
return numpy.frombuffer(level['Data'], dtype=numpy.uint8).reshape((16,16,64))
|
||||
return level['Data']
|
||||
|
||||
def get_tileentity_data(level):
|
||||
"""Returns the TileEntities TAG_List from chunk dat file"""
|
||||
|
||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
BIN
overviewer_core/data/web_assets/compass_lower-right.png
Normal file
BIN
overviewer_core/data/web_assets/compass_lower-right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
BIN
overviewer_core/data/web_assets/compass_upper-left.png
Normal file
BIN
overviewer_core/data/web_assets/compass_upper-left.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
BIN
overviewer_core/data/web_assets/compass_upper-right.png
Normal file
BIN
overviewer_core/data/web_assets/compass_upper-right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
@@ -536,6 +536,19 @@ var overviewer = {
|
||||
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
|
||||
Math.pow(2, overviewerConfig.map.zoomLevels));
|
||||
|
||||
if(overviewerConfig.map.north_direction == 'upper-left'){
|
||||
temp = x;
|
||||
x = -y-1;
|
||||
y = temp;
|
||||
} else if(overviewerConfig.map.north_direction == 'upper-right'){
|
||||
x = -x-1;
|
||||
y = -y-1;
|
||||
} else if(overviewerConfig.map.north_direction == 'lower-right'){
|
||||
temp = x;
|
||||
x = y;
|
||||
y = -temp-1;
|
||||
}
|
||||
|
||||
// This information about where the center column is may change with
|
||||
// a different drawing implementation -- check it again after any
|
||||
// drawing overhauls!
|
||||
@@ -607,6 +620,19 @@ var overviewer = {
|
||||
point.x += 64;
|
||||
point.z -= 64;
|
||||
|
||||
if(overviewerConfig.map.north_direction == 'upper-left'){
|
||||
temp = point.z;
|
||||
point.z = -point.x;
|
||||
point.x = temp;
|
||||
} else if(overviewerConfig.map.north_direction == 'upper-right'){
|
||||
point.x = -point.x;
|
||||
point.z = -point.z;
|
||||
} else if(overviewerConfig.map.north_direction == 'lower-right'){
|
||||
temp = point.z;
|
||||
point.z = point.x;
|
||||
point.x = -temp;
|
||||
}
|
||||
|
||||
return point;
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ var overviewerConfig = {
|
||||
'image': {
|
||||
'defaultMarker': 'signpost.png',
|
||||
'signMarker': 'signpost_icon.png',
|
||||
'compass': 'compass.png',
|
||||
'compass': 'compass_{north_direction}.png',
|
||||
'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png',
|
||||
'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.png'
|
||||
},
|
||||
@@ -94,7 +94,11 @@ var overviewerConfig = {
|
||||
* Set to true to turn on debug mode, which adds a grid to the map along
|
||||
* with co-ordinates and a bunch of console output.
|
||||
*/
|
||||
'debug': false
|
||||
'debug': false,
|
||||
/**
|
||||
* Set which way north points.
|
||||
*/
|
||||
'north_direction': '{north_direction}'
|
||||
},
|
||||
/**
|
||||
* Group definitions for objects that are partially selectable (signs and
|
||||
|
||||
@@ -77,6 +77,7 @@ class MapGen(object):
|
||||
self.web_assets_hook = configInfo.get('web_assets_hook', None)
|
||||
self.web_assets_path = configInfo.get('web_assets_path', None)
|
||||
self.bg_color = configInfo.get('bg_color')
|
||||
self.north_direction = configInfo.get('north_direction', 'lower-left')
|
||||
|
||||
if not len(quadtrees) > 0:
|
||||
raise ValueError("there must be at least one quadtree to work on")
|
||||
@@ -121,6 +122,8 @@ class MapGen(object):
|
||||
"{maxzoom}", str(zoomlevel))
|
||||
config = config.replace(
|
||||
"{zoomlevels}", str(zoomlevel))
|
||||
config = config.replace(
|
||||
"{north_direction}", self.north_direction)
|
||||
|
||||
config = config.replace("{spawn_coords}",
|
||||
json.dumps(list(self.world.spawn)))
|
||||
|
||||
@@ -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,14 +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):
|
||||
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
|
||||
location table."""
|
||||
@@ -318,21 +330,24 @@ class MCRFileReader(object):
|
||||
self.openfile()
|
||||
|
||||
self._chunks = None
|
||||
self._locations = []
|
||||
self._locations = [0]*32*32
|
||||
self._timestamps = []
|
||||
|
||||
# go to the beginning of the file
|
||||
self._file.seek(0)
|
||||
|
||||
# read chunk location table
|
||||
locations_append = self._locations.append
|
||||
for _ in xrange(32*32):
|
||||
locations_append(self._read_chunk_location())
|
||||
locations_index = numpy.reshape(numpy.rot90(numpy.reshape(range(32*32),
|
||||
(32, 32)), -self.get_north_rotations()), -1)
|
||||
for i in locations_index:
|
||||
self._locations[i] = self._read_chunk_location()
|
||||
|
||||
# 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()
|
||||
|
||||
@@ -65,7 +65,8 @@ def pool_initializer(rendernode):
|
||||
|
||||
# make sure textures are generated for this process
|
||||
# and initialize c_overviewer
|
||||
textures.generate(path=rendernode.options.get('textures_path', None))
|
||||
textures.generate(path=rendernode.options.get('textures_path', None),
|
||||
north_direction=rendernode.options.get('north_direction', None))
|
||||
c_overviewer.init_chunk_render()
|
||||
|
||||
# load biome data in each process, if needed
|
||||
|
||||
@@ -513,6 +513,9 @@ def generate_texture_tuple(img, blockid):
|
||||
|
||||
def generate_special_texture(blockID, data):
|
||||
"""Generates a special texture, such as a correctly facing minecraft track"""
|
||||
|
||||
data = convert_data(blockID, data)
|
||||
|
||||
# blocks need to be handled here (and in chunk.py)
|
||||
|
||||
if blockID == 2: # grass
|
||||
@@ -1679,6 +1682,237 @@ def generate_special_texture(blockID, data):
|
||||
|
||||
return None
|
||||
|
||||
def convert_data(blockID, data):
|
||||
if blockID == 26: # bed
|
||||
#Masked to not clobber block head/foot info
|
||||
if _north == 'upper-left':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 0
|
||||
elif _north == 'upper-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 1
|
||||
elif _north == 'lower-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 2
|
||||
if blockID in (29, 33, 34): # sticky piston, piston, piston extension
|
||||
#Masked to not clobber block head/foot info
|
||||
if _north == 'upper-left':
|
||||
if (data & 0b0111) == 2: data = data & 0b1000 | 5
|
||||
elif (data & 0b0111) == 3: data = data & 0b1000 | 4
|
||||
elif (data & 0b0111) == 4: data = data & 0b1000 | 2
|
||||
elif (data & 0b0111) == 5: data = data & 0b1000 | 3
|
||||
elif _north == 'upper-right':
|
||||
if (data & 0b0111) == 2: data = data & 0b1000 | 3
|
||||
elif (data & 0b0111) == 3: data = data & 0b1000 | 2
|
||||
elif (data & 0b0111) == 4: data = data & 0b1000 | 5
|
||||
elif (data & 0b0111) == 5: data = data & 0b1000 | 4
|
||||
elif _north == 'lower-right':
|
||||
if (data & 0b0111) == 2: data = data & 0b1000 | 4
|
||||
elif (data & 0b0111) == 3: data = data & 0b1000 | 5
|
||||
elif (data & 0b0111) == 4: data = data & 0b1000 | 3
|
||||
elif (data & 0b0111) == 5: data = data & 0b1000 | 2
|
||||
if blockID in (27, 28, 66): # minetrack:
|
||||
#Masked to not clobber powered rail on/off info
|
||||
#Ascending and flat straight
|
||||
if _north == 'upper-left':
|
||||
if (data & 0b0111) == 0: data = data & 0b1000 | 1
|
||||
elif (data & 0b0111) == 1: data = data & 0b1000 | 0
|
||||
elif (data & 0b0111) == 2: data = data & 0b1000 | 5
|
||||
elif (data & 0b0111) == 3: data = data & 0b1000 | 4
|
||||
elif (data & 0b0111) == 4: data = data & 0b1000 | 2
|
||||
elif (data & 0b0111) == 5: data = data & 0b1000 | 3
|
||||
elif _north == 'upper-right':
|
||||
if (data & 0b0111) == 2: data = data & 0b1000 | 3
|
||||
elif (data & 0b0111) == 3: data = data & 0b1000 | 2
|
||||
elif (data & 0b0111) == 4: data = data & 0b1000 | 5
|
||||
elif (data & 0b0111) == 5: data = data & 0b1000 | 4
|
||||
elif _north == 'lower-right':
|
||||
if (data & 0b0111) == 0: data = data & 0b1000 | 1
|
||||
elif (data & 0b0111) == 1: data = data & 0b1000 | 0
|
||||
elif (data & 0b0111) == 2: data = data & 0b1000 | 4
|
||||
elif (data & 0b0111) == 3: data = data & 0b1000 | 5
|
||||
elif (data & 0b0111) == 4: data = data & 0b1000 | 3
|
||||
elif (data & 0b0111) == 5: data = data & 0b1000 | 2
|
||||
if blockID == 66: # normal minetrack only
|
||||
#Corners
|
||||
if _north == 'upper-left':
|
||||
if data == 6: data = 7
|
||||
elif data == 7: data = 8
|
||||
elif data == 8: data = 6
|
||||
elif data == 9: data = 9
|
||||
elif _north == 'upper-right':
|
||||
if data == 6: data = 8
|
||||
elif data == 7: data = 9
|
||||
elif data == 8: data = 6
|
||||
elif data == 9: data = 7
|
||||
elif _north == 'lower-right':
|
||||
if data == 6: data = 9
|
||||
elif data == 7: data = 6
|
||||
elif data == 8: data = 8
|
||||
elif data == 9: data = 7
|
||||
if blockID in (50, 75, 76): # torch, off/on redstone torch
|
||||
if _north == 'upper-left':
|
||||
if data == 1: data = 3
|
||||
elif data == 2: data = 4
|
||||
elif data == 3: data = 2
|
||||
elif data == 4: data = 1
|
||||
elif _north == 'upper-right':
|
||||
if data == 1: data = 2
|
||||
elif data == 2: data = 1
|
||||
elif data == 3: data = 4
|
||||
elif data == 4: data = 3
|
||||
elif _north == 'lower-right':
|
||||
if data == 1: data = 4
|
||||
elif data == 2: data = 3
|
||||
elif data == 3: data = 1
|
||||
elif data == 4: data = 2
|
||||
if blockID in (53,67): # wooden and cobblestone stairs.
|
||||
if _north == 'upper-left':
|
||||
if data == 0: data = 2
|
||||
elif data == 1: data = 3
|
||||
elif data == 2: data = 1
|
||||
elif data == 3: data = 0
|
||||
elif _north == 'upper-right':
|
||||
if data == 0: data = 1
|
||||
elif data == 1: data = 0
|
||||
elif data == 2: data = 3
|
||||
elif data == 3: data = 2
|
||||
elif _north == 'lower-right':
|
||||
if data == 0: data = 3
|
||||
elif data == 1: data = 2
|
||||
elif data == 2: data = 0
|
||||
elif data == 3: data = 1
|
||||
if blockID in (61, 62, 23): # furnace and burning furnace
|
||||
if _north == 'upper-left':
|
||||
if data == 2: data = 5
|
||||
elif data == 3: data = 4
|
||||
elif data == 4: data = 2
|
||||
elif data == 5: data = 3
|
||||
elif _north == 'upper-right':
|
||||
if data == 2: data = 3
|
||||
elif data == 3: data = 2
|
||||
elif data == 4: data = 5
|
||||
elif data == 5: data = 4
|
||||
elif _north == 'lower-right':
|
||||
if data == 2: data = 4
|
||||
elif data == 3: data = 5
|
||||
elif data == 4: data = 3
|
||||
elif data == 5: data = 2
|
||||
if blockID == 63: # signposts
|
||||
if _north == 'upper-left':
|
||||
data = (data + 4) % 16
|
||||
elif _north == 'upper-right':
|
||||
data = (data + 8) % 16
|
||||
elif _north == 'lower-right':
|
||||
data = (data + 12) % 16
|
||||
if blockID in (64,71): # wooden/iron door
|
||||
#Masked to not clobber block top/bottom & swung info
|
||||
if _north == 'upper-left':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 0
|
||||
elif _north == 'upper-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 1
|
||||
elif _north == 'lower-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 2
|
||||
if blockID == 65: # ladder
|
||||
if _north == 'upper-left':
|
||||
if data == 2: data = 5
|
||||
elif data == 3: data = 4
|
||||
elif data == 4: data = 2
|
||||
elif data == 5: data = 3
|
||||
elif _north == 'upper-right':
|
||||
if data == 2: data = 3
|
||||
elif data == 3: data = 2
|
||||
elif data == 4: data = 5
|
||||
elif data == 5: data = 4
|
||||
elif _north == 'lower-right':
|
||||
if data == 2: data = 4
|
||||
elif data == 3: data = 5
|
||||
elif data == 4: data = 3
|
||||
elif data == 5: data = 2
|
||||
if blockID == 68: # wall sign
|
||||
if _north == 'upper-left':
|
||||
if data == 2: data = 5
|
||||
elif data == 3: data = 4
|
||||
elif data == 4: data = 2
|
||||
elif data == 5: data = 3
|
||||
elif _north == 'upper-right':
|
||||
if data == 2: data = 3
|
||||
elif data == 3: data = 2
|
||||
elif data == 4: data = 5
|
||||
elif data == 5: data = 4
|
||||
elif _north == 'lower-right':
|
||||
if data == 2: data = 4
|
||||
elif data == 3: data = 5
|
||||
elif data == 4: data = 3
|
||||
elif data == 5: data = 2
|
||||
if blockID in (86,91): # pumpkins, jack-o-lantern
|
||||
if _north == 'upper-left':
|
||||
if data == 0: data = 1
|
||||
elif data == 1: data = 2
|
||||
elif data == 2: data = 3
|
||||
elif data == 3: data = 0
|
||||
elif _north == 'upper-right':
|
||||
if data == 0: data = 2
|
||||
elif data == 1: data = 3
|
||||
elif data == 2: data = 0
|
||||
elif data == 3: data = 1
|
||||
elif _north == 'lower-right':
|
||||
if data == 0: data = 3
|
||||
elif data == 1: data = 0
|
||||
elif data == 2: data = 1
|
||||
elif data == 3: data = 2
|
||||
if blockID in (93, 94): # redstone repeaters, ON and OFF
|
||||
#Masked to not clobber delay info
|
||||
if _north == 'upper-left':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 0
|
||||
elif _north == 'upper-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 1
|
||||
elif _north == 'lower-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 2
|
||||
if blockID == 96: # trapdoor
|
||||
#Masked to not clobber opened/closed info
|
||||
if _north == 'upper-left':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 1
|
||||
elif _north == 'upper-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 0
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 2
|
||||
elif _north == 'lower-right':
|
||||
if (data & 0b0011) == 0: data = data & 0b1100 | 2
|
||||
elif (data & 0b0011) == 1: data = data & 0b1100 | 3
|
||||
elif (data & 0b0011) == 2: data = data & 0b1100 | 1
|
||||
elif (data & 0b0011) == 3: data = data & 0b1100 | 0
|
||||
|
||||
return data
|
||||
|
||||
def tintTexture(im, c):
|
||||
# apparently converting to grayscale drops the alpha channel?
|
||||
i = ImageOps.colorize(ImageOps.grayscale(im), (0,0,0), c)
|
||||
@@ -1722,8 +1956,25 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
||||
'''
|
||||
|
||||
global currentBiomeFile, currentBiomeData
|
||||
biomeX = chunkX // 32
|
||||
biomeY = chunkY // 32
|
||||
rots = 0
|
||||
if _north == 'upper-left':
|
||||
temp = biomeX
|
||||
biomeX = biomeY
|
||||
biomeY = -temp-1
|
||||
rots = 3
|
||||
elif _north == 'upper-right':
|
||||
biomeX = -biomeX-1
|
||||
biomeY = -biomeY-1
|
||||
rots = 2
|
||||
elif _north == 'lower-right':
|
||||
temp = biomeX
|
||||
biomeX = -biomeY-1
|
||||
biomeY = temp
|
||||
rots = 1
|
||||
|
||||
biomeFile = "b.%d.%d.biome" % (chunkX // 32, chunkY // 32)
|
||||
biomeFile = "b.%d.%d.biome" % (biomeX, biomeY)
|
||||
if biomeFile == currentBiomeFile:
|
||||
return currentBiomeData
|
||||
|
||||
@@ -1733,7 +1984,9 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
||||
# make sure the file size is correct
|
||||
if not len(rawdata) == 512 * 512 * 2:
|
||||
raise Exception("Biome file %s is not valid." % (biomeFile,))
|
||||
data = numpy.frombuffer(rawdata, dtype=numpy.dtype(">u2"))
|
||||
data = numpy.reshape(numpy.rot90(numpy.reshape(
|
||||
numpy.frombuffer(rawdata, dtype=numpy.dtype(">u2")),
|
||||
(512,512)),rots), -1)
|
||||
except IOError:
|
||||
data = None
|
||||
pass # no biome data
|
||||
@@ -1822,7 +2075,10 @@ biome_tall_fern_texture = None
|
||||
biome_leaf_texture = None
|
||||
specialblockmap = None
|
||||
|
||||
def generate(path=None,texture_size=24,bgc = (26,26,26,0)):
|
||||
def generate(path=None,texture_size=24,bgc = (26,26,26,0),north_direction='lower-left'):
|
||||
global _north
|
||||
_north = north_direction
|
||||
global _find_file_local_path
|
||||
global bgcolor
|
||||
bgcolor = bgc
|
||||
global _find_file_local_path, texture_dimensions
|
||||
|
||||
@@ -69,10 +69,11 @@ class World(object):
|
||||
|
||||
mincol = maxcol = minrow = maxrow = 0
|
||||
|
||||
def __init__(self, worlddir, outputdir, useBiomeData=False,regionlist=None):
|
||||
def __init__(self, worlddir, outputdir, useBiomeData=False, regionlist=None, north_direction="lower-left"):
|
||||
self.worlddir = worlddir
|
||||
self.outputdir = outputdir
|
||||
self.useBiomeData = useBiomeData
|
||||
self.north_direction = north_direction
|
||||
|
||||
#find region files, or load the region list
|
||||
#this also caches all the region file header info
|
||||
@@ -169,6 +170,18 @@ class World(object):
|
||||
data = nbt.read_all()
|
||||
level = data[1]['Level']
|
||||
chunk_data = level
|
||||
chunk_data['Blocks'] = numpy.array(numpy.rot90(numpy.frombuffer(
|
||||
level['Blocks'], dtype=numpy.uint8).reshape((16,16,128)),
|
||||
self._get_north_rotations()))
|
||||
chunk_data['Data'] = numpy.array(numpy.rot90(numpy.frombuffer(
|
||||
level['Data'], dtype=numpy.uint8).reshape((16,16,64)),
|
||||
self._get_north_rotations()))
|
||||
chunk_data['SkyLight'] = numpy.array(numpy.rot90(numpy.frombuffer(
|
||||
level['SkyLight'], dtype=numpy.uint8).reshape((16,16,64)),
|
||||
self._get_north_rotations()))
|
||||
chunk_data['BlockLight'] = numpy.array(numpy.rot90(numpy.frombuffer(
|
||||
level['BlockLight'], dtype=numpy.uint8).reshape((16,16,64)),
|
||||
self._get_north_rotations()))
|
||||
#chunk_data = {}
|
||||
#chunk_data['skylight'] = chunk.get_skylight_array(level)
|
||||
#chunk_data['blocklight'] = chunk.get_blocklight_array(level)
|
||||
@@ -185,7 +198,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
|
||||
|
||||
@@ -201,7 +214,7 @@ class World(object):
|
||||
in the image each one should be. Returns (col, row)."""
|
||||
|
||||
# columns are determined by the sum of the chunk coords, rows are the
|
||||
# difference (TODO: be able to change direction of north)
|
||||
# difference
|
||||
# change this function, and you MUST change unconvert_coords
|
||||
return (chunkx + chunky, chunky - chunkx)
|
||||
|
||||
@@ -219,9 +232,20 @@ class World(object):
|
||||
|
||||
## read spawn info from level.dat
|
||||
data = nbt.load(os.path.join(self.worlddir, "level.dat"))[1]
|
||||
spawnX = data['Data']['SpawnX']
|
||||
disp_spawnX = spawnX = data['Data']['SpawnX']
|
||||
spawnY = data['Data']['SpawnY']
|
||||
spawnZ = data['Data']['SpawnZ']
|
||||
disp_spawnZ = spawnZ = data['Data']['SpawnZ']
|
||||
if self.north_direction == 'upper-left':
|
||||
temp = spawnX
|
||||
spawnX = -spawnZ
|
||||
spawnZ = temp
|
||||
elif self.north_direction == 'upper-right':
|
||||
spawnX = -spawnX
|
||||
spawnZ = -spawnZ
|
||||
elif self.north_direction == 'lower-right':
|
||||
temp = spawnX
|
||||
spawnX = spawnZ
|
||||
spawnZ = -temp
|
||||
|
||||
## The chunk that holds the spawn location
|
||||
chunkX = spawnX/16
|
||||
@@ -231,7 +255,7 @@ class World(object):
|
||||
## The filename of this chunk
|
||||
chunkFile = self.get_region_path(chunkX, chunkY)
|
||||
if chunkFile is not None:
|
||||
data = nbt.load_from_region(chunkFile, chunkX, chunkY)[1]
|
||||
data = nbt.load_from_region(chunkFile, chunkX, chunkY, self.north_direction)[1]
|
||||
if data is not None:
|
||||
level = data['Level']
|
||||
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
||||
@@ -248,9 +272,9 @@ class World(object):
|
||||
except ChunkCorrupt:
|
||||
#ignore corrupt spawn, and continue
|
||||
pass
|
||||
self.POI.append( dict(x=spawnX, y=spawnY, z=spawnZ,
|
||||
self.POI.append( dict(x=disp_spawnX, y=spawnY, z=disp_spawnZ,
|
||||
msg="Spawn", type="spawn", chunk=(chunkX, chunkY)))
|
||||
self.spawn = (spawnX, spawnY, spawnZ)
|
||||
self.spawn = (disp_spawnX, spawnY, disp_spawnZ)
|
||||
|
||||
def go(self, procs):
|
||||
"""Scan the world directory, to fill in
|
||||
@@ -296,6 +320,16 @@ class World(object):
|
||||
|
||||
self.findTrueSpawn()
|
||||
|
||||
def _get_north_rotations(self):
|
||||
if self.north_direction == 'upper-left':
|
||||
return 1
|
||||
elif self.north_direction == 'upper-right':
|
||||
return 2
|
||||
elif self.north_direction == 'lower-right':
|
||||
return 3
|
||||
elif self.north_direction == 'lower-left':
|
||||
return 0
|
||||
|
||||
def _iterate_regionfiles(self,regionlist=None):
|
||||
"""Returns an iterator of all of the region files, along with their
|
||||
coordinates
|
||||
@@ -312,7 +346,20 @@ class World(object):
|
||||
if f.startswith("r.") and f.endswith(".mcr"):
|
||||
p = f.split(".")
|
||||
logging.debug("Using path %s from regionlist", f)
|
||||
yield (int(p[1]), int(p[2]), join(self.worlddir, 'region', f))
|
||||
x = int(p[1])
|
||||
y = int(p[2])
|
||||
if self.north_direction == 'upper-left':
|
||||
temp = x
|
||||
x = -y-1
|
||||
y = temp
|
||||
elif self.north_direction == 'upper-right':
|
||||
x = -x-1
|
||||
y = -y-1
|
||||
elif self.north_direction == 'lower-right':
|
||||
temp = x
|
||||
x = y
|
||||
y = -temp-1
|
||||
yield (x, y, join(self.worlddir, 'region', f))
|
||||
else:
|
||||
logging.warning("Ignore path '%s' in regionlist", f)
|
||||
|
||||
@@ -320,7 +367,20 @@ class World(object):
|
||||
for path in glob(os.path.join(self.worlddir, 'region') + "/r.*.*.mcr"):
|
||||
dirpath, f = os.path.split(path)
|
||||
p = f.split(".")
|
||||
yield (int(p[1]), int(p[2]), join(dirpath, f))
|
||||
x = int(p[1])
|
||||
y = int(p[2])
|
||||
if self.north_direction == 'upper-left':
|
||||
temp = x
|
||||
x = -y-1
|
||||
y = temp
|
||||
elif self.north_direction == 'upper-right':
|
||||
x = -x-1
|
||||
y = -y-1
|
||||
elif self.north_direction == 'lower-right':
|
||||
temp = x
|
||||
x = y
|
||||
y = -temp-1
|
||||
yield (x, y, join(dirpath, f))
|
||||
|
||||
def get_save_dir():
|
||||
"""Returns the path to the local saves directory
|
||||
|
||||
@@ -152,6 +152,14 @@ verbose = 1
|
||||
if "web_assets_hook" in locals():
|
||||
skipjs = True
|
||||
|
||||
################################################################################
|
||||
### north_direction
|
||||
## Make north point somewhere else!
|
||||
## Valid options are 'lower-left', 'upper-left', 'upper-right', 'upper-left'
|
||||
## default: lower-left
|
||||
## Type: string
|
||||
## Example:
|
||||
north_direction = "upper-right"
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user