Merge remote-tracking branch 'upstream/master' into contribs
Conflicts: setup.py
This commit is contained in:
@@ -52,9 +52,11 @@ feature.
|
|||||||
* Ryan Hitchman <hitchmanr@gmail.com>
|
* Ryan Hitchman <hitchmanr@gmail.com>
|
||||||
* Jenny <jennytoo@gmail.com>
|
* Jenny <jennytoo@gmail.com>
|
||||||
* Michael Jensen <emjay1988@gmail.com>
|
* Michael Jensen <emjay1988@gmail.com>
|
||||||
* Maciej Małecki <maciej.malecki@hotmail.com>
|
* Thomas Lake <tswsl1989@sucs.org>
|
||||||
|
* Maciej Malecki <maciej.malecki@hotmail.com>
|
||||||
* Ryan McCue <ryanmccue@cubegames.net>
|
* Ryan McCue <ryanmccue@cubegames.net>
|
||||||
* Morlok8k <otis.spankmeyer@gmail.com>
|
* Morlok8k <otis.spankmeyer@gmail.com>
|
||||||
|
* Ryan Rector <rmrector@gmail.com>
|
||||||
* Gregory Short <gshort2@gmail.com>
|
* Gregory Short <gshort2@gmail.com>
|
||||||
* Sam Steele <sam@sigbox.c99.org>
|
* Sam Steele <sam@sigbox.c99.org>
|
||||||
* timwolla <timwolla@mail.develfusion.com>
|
* timwolla <timwolla@mail.develfusion.com>
|
||||||
|
|||||||
15
README.rst
15
README.rst
@@ -195,6 +195,13 @@ Options
|
|||||||
--list-rendermodes
|
--list-rendermodes
|
||||||
List the available render modes, and a short description of each.
|
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.
|
||||||
|
If you do not specify this option, it will default to whatever direction
|
||||||
|
the existing map uses. For new maps, it defaults to lower-left for
|
||||||
|
historical reasons.
|
||||||
|
|
||||||
--settings=PATH
|
--settings=PATH
|
||||||
Use this option to load settings from a file. The format of this file is
|
Use this option to load settings from a file. The format of this file is
|
||||||
given below.
|
given below.
|
||||||
@@ -228,8 +235,8 @@ zoom=ZOOM
|
|||||||
|
|
||||||
This is equivalent to setting the dimensions of the highest zoom level. It
|
This is equivalent to setting the dimensions of the highest zoom level. It
|
||||||
does not actually change how the map is rendered, but rather *how much of
|
does not actually change how the map is rendered, but rather *how much of
|
||||||
the map is rendered.* (Calling this option "zoom" may be a bit misleading,
|
the map is rendered.* Setting this option too low *will crop your map.*
|
||||||
I know)
|
(Calling this option "zoom" may be a bit misleading, I know)
|
||||||
|
|
||||||
To be precise, it sets the width and height of the highest zoom level, in
|
To be precise, it sets the width and height of the highest zoom level, in
|
||||||
tiles. A zoom level of z means the highest zoom level of your map will be
|
tiles. A zoom level of z means the highest zoom level of your map will be
|
||||||
@@ -264,6 +271,10 @@ textures_path
|
|||||||
source. Overviewer looks in here for terrain.png and other textures before
|
source. Overviewer looks in here for terrain.png and other textures before
|
||||||
it looks anywhere else.
|
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
|
Viewing the Results
|
||||||
-------------------
|
-------------------
|
||||||
Within the output directory you will find two things: an index.html file, and a
|
Within the output directory you will find two things: an index.html file, and a
|
||||||
|
|||||||
18
contrib/playerInspect.py
Normal file
18
contrib/playerInspect.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append(".")
|
||||||
|
|
||||||
|
from overviewer_core.nbt import load
|
||||||
|
from overviewer_core import items
|
||||||
|
|
||||||
|
print "Inspecting %s" % sys.argv[1]
|
||||||
|
|
||||||
|
data = load(sys.argv[1])[1]
|
||||||
|
|
||||||
|
|
||||||
|
print "Position: %r" % data['Pos']
|
||||||
|
print "Health: %s" % data['Health']
|
||||||
|
print "Inventory: %d items" % len(data['Inventory'])
|
||||||
|
for item in data['Inventory']:
|
||||||
|
print " %-3d %s" % (item['Count'], items.id2item(item['id']))
|
||||||
|
|
||||||
@@ -96,6 +96,7 @@ def main():
|
|||||||
cpus = 1
|
cpus = 1
|
||||||
|
|
||||||
avail_rendermodes = c_overviewer.get_render_modes()
|
avail_rendermodes = c_overviewer.get_render_modes()
|
||||||
|
avail_north_dirs = ['lower-left', 'upper-left', 'upper-right', 'lower-right', 'auto']
|
||||||
|
|
||||||
parser = ConfigOptionParser(usage=helptext, config="settings.py")
|
parser = ConfigOptionParser(usage=helptext, config="settings.py")
|
||||||
parser.add_option("-V", "--version", dest="version", helptext="Displays version information and then exits", action="store_true")
|
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("-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("--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("--no-signs", dest="nosigns", action="store_true", helptext="Don't output signs to markers.js")
|
||||||
|
parser.add_option("--north-direction", dest="north_direction", action="store", helptext="Specifies which corner of the screen north will point to. Defaults to whatever the current map uses, or lower-left for new maps. Valid options are: " + ", ".join(avail_north_dirs) + ".", type="choice", default="auto", 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("--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)
|
#parser.add_option("--write-config", dest="write_config", action="store_true", helptext="Writes out a sample config file", commandLineOnly=True)
|
||||||
|
|
||||||
@@ -152,6 +154,17 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
worlddir = args[0]
|
worlddir = args[0]
|
||||||
|
|
||||||
|
if len(args) > 2:
|
||||||
|
# it's possible the user has a space in one of their paths but didn't properly escape it
|
||||||
|
# attempt to detect this case
|
||||||
|
for start in range(len(args)):
|
||||||
|
if not os.path.exists(args[start]):
|
||||||
|
for end in range(start+1, len(args)+1):
|
||||||
|
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)
|
||||||
|
|
||||||
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
|
||||||
worlds = world.get_worlds()
|
worlds = world.get_worlds()
|
||||||
@@ -219,6 +232,11 @@ def main():
|
|||||||
optimizeimages.check_programs(optimizeimg)
|
optimizeimages.check_programs(optimizeimg)
|
||||||
else:
|
else:
|
||||||
optimizeimg = None
|
optimizeimg = None
|
||||||
|
|
||||||
|
if options.north_direction:
|
||||||
|
north_direction = options.north_direction
|
||||||
|
else:
|
||||||
|
north_direction = 'auto'
|
||||||
|
|
||||||
logging.getLogger().setLevel(
|
logging.getLogger().setLevel(
|
||||||
logging.getLogger().level + 10*options.quiet)
|
logging.getLogger().level + 10*options.quiet)
|
||||||
@@ -233,7 +251,17 @@ def main():
|
|||||||
logging.info("Notice: Not using biome data for tinting")
|
logging.info("Notice: Not using biome data for tinting")
|
||||||
|
|
||||||
# First do world-level preprocessing
|
# 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)
|
||||||
|
if north_direction == 'auto':
|
||||||
|
north_direction = w.persistentData['north_direction']
|
||||||
|
options.north_direction = north_direction
|
||||||
|
elif w.persistentData['north_direction'] != north_direction and not options.forcerender and not w.persistentDataIsNew:
|
||||||
|
logging.error("Conflicting north-direction setting!")
|
||||||
|
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, --forcerender must be specified")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
w.go(options.procs)
|
w.go(options.procs)
|
||||||
|
|
||||||
logging.info("Rending the following tilesets: %s", ",".join(options.rendermode))
|
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):
|
def get_blockarray(level):
|
||||||
"""Takes the level struct as returned from get_lvldata, and returns the
|
"""Takes the level struct as returned from get_lvldata, and returns the
|
||||||
Block array, which just contains all the block ids"""
|
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"""
|
"""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']
|
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):
|
def get_skylight_array(level):
|
||||||
"""Returns the skylight array. This is 4 bits per block, but it is
|
"""Returns the skylight array. This is 4 bits per block, but it is
|
||||||
expanded for you so you may index it normally."""
|
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
|
# this array is 2 blocks per byte, so expand it
|
||||||
skylight_expanded = numpy.empty((16,16,128), dtype=numpy.uint8)
|
skylight_expanded = numpy.empty((16,16,128), dtype=numpy.uint8)
|
||||||
# Even elements get the lower 4 bits
|
# 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
|
"""Returns the blocklight array. This is 4 bits per block, but it
|
||||||
is expanded for you so you may index it normally."""
|
is expanded for you so you may index it normally."""
|
||||||
# expand just like get_skylight_array()
|
# 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 = numpy.empty((16,16,128), dtype=numpy.uint8)
|
||||||
blocklight_expanded[:,:,::2] = blocklight & 0x0F
|
blocklight_expanded[:,:,::2] = blocklight & 0x0F
|
||||||
blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4
|
blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4
|
||||||
@@ -106,7 +118,7 @@ def get_blocklight_array(level):
|
|||||||
def get_blockdata_array(level):
|
def get_blockdata_array(level):
|
||||||
"""Returns the ancillary data from the 'Data' byte array. Data is packed
|
"""Returns the ancillary data from the 'Data' byte array. Data is packed
|
||||||
in a similar manner to skylight data"""
|
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):
|
def get_tileentity_data(level):
|
||||||
"""Returns the TileEntities TAG_List from chunk dat file"""
|
"""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 *
|
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
|
||||||
Math.pow(2, overviewerConfig.map.zoomLevels));
|
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
|
// This information about where the center column is may change with
|
||||||
// a different drawing implementation -- check it again after any
|
// a different drawing implementation -- check it again after any
|
||||||
// drawing overhauls!
|
// drawing overhauls!
|
||||||
@@ -607,6 +620,19 @@ var overviewer = {
|
|||||||
point.x += 64;
|
point.x += 64;
|
||||||
point.z -= 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;
|
return point;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ var overviewerConfig = {
|
|||||||
'image': {
|
'image': {
|
||||||
'defaultMarker': 'signpost.png',
|
'defaultMarker': 'signpost.png',
|
||||||
'signMarker': 'signpost_icon.png',
|
'signMarker': 'signpost_icon.png',
|
||||||
'compass': 'compass.png',
|
'compass': 'compass_{north_direction}.png',
|
||||||
'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png',
|
'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png',
|
||||||
'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.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
|
* 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.
|
* 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
|
* 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_hook = configInfo.get('web_assets_hook', None)
|
||||||
self.web_assets_path = configInfo.get('web_assets_path', None)
|
self.web_assets_path = configInfo.get('web_assets_path', None)
|
||||||
self.bg_color = configInfo.get('bg_color')
|
self.bg_color = configInfo.get('bg_color')
|
||||||
|
self.north_direction = configInfo.get('north_direction', 'lower-left')
|
||||||
|
|
||||||
if not len(quadtrees) > 0:
|
if not len(quadtrees) > 0:
|
||||||
raise ValueError("there must be at least one quadtree to work on")
|
raise ValueError("there must be at least one quadtree to work on")
|
||||||
@@ -121,6 +122,8 @@ class MapGen(object):
|
|||||||
"{maxzoom}", str(zoomlevel))
|
"{maxzoom}", str(zoomlevel))
|
||||||
config = config.replace(
|
config = config.replace(
|
||||||
"{zoomlevels}", str(zoomlevel))
|
"{zoomlevels}", str(zoomlevel))
|
||||||
|
config = config.replace(
|
||||||
|
"{north_direction}", self.north_direction)
|
||||||
|
|
||||||
config = config.replace("{spawn_coords}",
|
config = config.replace("{spawn_coords}",
|
||||||
json.dumps(list(self.world.spawn)))
|
json.dumps(list(self.world.spawn)))
|
||||||
@@ -157,9 +160,6 @@ class MapGen(object):
|
|||||||
|
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
if self.skipjs:
|
|
||||||
return
|
|
||||||
|
|
||||||
# since we will only discover PointsOfInterest in chunks that need to be
|
# since we will only discover PointsOfInterest in chunks that need to be
|
||||||
# [re]rendered, POIs like signs in unchanged chunks will not be listed
|
# [re]rendered, POIs like signs in unchanged chunks will not be listed
|
||||||
# in self.world.POI. To make sure we don't remove these from markers.js
|
# in self.world.POI. To make sure we don't remove these from markers.js
|
||||||
@@ -172,6 +172,17 @@ class MapGen(object):
|
|||||||
else:
|
else:
|
||||||
markers = self.world.POI
|
markers = self.world.POI
|
||||||
|
|
||||||
|
# save persistent data
|
||||||
|
self.world.persistentData['POI'] = self.world.POI
|
||||||
|
self.world.persistentData['north_direction'] = self.world.north_direction
|
||||||
|
with open(self.world.pickleFile,"wb") as f:
|
||||||
|
cPickle.dump(self.world.persistentData,f)
|
||||||
|
|
||||||
|
|
||||||
|
# the rest of the function is javascript stuff
|
||||||
|
if self.skipjs:
|
||||||
|
return
|
||||||
|
|
||||||
# write out the default marker table
|
# write out the default marker table
|
||||||
with open(os.path.join(self.destdir, "markers.js"), 'w') as output:
|
with open(os.path.join(self.destdir, "markers.js"), 'w') as output:
|
||||||
output.write("overviewer.collections.markerDatas.push([\n")
|
output.write("overviewer.collections.markerDatas.push([\n")
|
||||||
@@ -182,11 +193,6 @@ class MapGen(object):
|
|||||||
output.write("\n")
|
output.write("\n")
|
||||||
output.write("]);\n")
|
output.write("]);\n")
|
||||||
|
|
||||||
# save persistent data
|
|
||||||
self.world.persistentData['POI'] = self.world.POI
|
|
||||||
with open(self.world.pickleFile,"wb") as f:
|
|
||||||
cPickle.dump(self.world.persistentData,f)
|
|
||||||
|
|
||||||
# write out the default (empty, but documented) region table
|
# write out the default (empty, but documented) region table
|
||||||
with open(os.path.join(self.destdir, "regions.js"), 'w') as output:
|
with open(os.path.join(self.destdir, "regions.js"), 'w') as output:
|
||||||
output.write('overviewer.collections.regionDatas.push([\n')
|
output.write('overviewer.collections.regionDatas.push([\n')
|
||||||
|
|||||||
211
overviewer_core/items.py
Normal file
211
overviewer_core/items.py
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
items = {
|
||||||
|
0: 'Air',
|
||||||
|
1: 'Stone',
|
||||||
|
2: 'Grass',
|
||||||
|
3: 'Dirt',
|
||||||
|
4: 'Cobblestone',
|
||||||
|
5: 'Wooden plank',
|
||||||
|
6: 'Sapling',
|
||||||
|
7: 'Bedrock',
|
||||||
|
8: 'Water',
|
||||||
|
9: 'Stationary',
|
||||||
|
10: 'Lava',
|
||||||
|
11: 'Stationary',
|
||||||
|
12: 'Sand',
|
||||||
|
13: 'Gravel',
|
||||||
|
14: 'Gold ore',
|
||||||
|
15: 'Iron ore',
|
||||||
|
16: 'Coal ore',
|
||||||
|
17: 'Wood',
|
||||||
|
18: 'Leaves',
|
||||||
|
19: 'Sponge',
|
||||||
|
20: 'Glass',
|
||||||
|
21: 'Lapis lazuli ore',
|
||||||
|
22: 'Lapis lazuli block',
|
||||||
|
23: 'Dispenser',
|
||||||
|
24: 'Sandstone',
|
||||||
|
25: 'Note block',
|
||||||
|
26: 'Bed',
|
||||||
|
27: 'Powered rail',
|
||||||
|
28: 'Detector rail',
|
||||||
|
29: 'Sticky piston',
|
||||||
|
30: 'Cobweb',
|
||||||
|
31: 'Tall grass',
|
||||||
|
32: 'Dead shrubs',
|
||||||
|
33: 'Piston',
|
||||||
|
34: 'Piston extension',
|
||||||
|
35: 'Wool',
|
||||||
|
36: 'Block moved by piston',
|
||||||
|
37: 'Dandelion',
|
||||||
|
38: 'Rose',
|
||||||
|
39: 'Brown mushroom',
|
||||||
|
40: 'Red mushroom',
|
||||||
|
41: 'Block of gold',
|
||||||
|
42: 'Block of iron',
|
||||||
|
43: 'Double slabs',
|
||||||
|
44: 'Slabs',
|
||||||
|
45: 'Brick block',
|
||||||
|
46: 'TNT',
|
||||||
|
47: 'Bookshelf',
|
||||||
|
48: 'Moss stone',
|
||||||
|
49: 'Obsidian',
|
||||||
|
50: 'Torch',
|
||||||
|
51: 'Fire',
|
||||||
|
52: 'Monster spawner',
|
||||||
|
53: 'Wooden stairs',
|
||||||
|
54: 'Chest',
|
||||||
|
55: 'Redstone wire',
|
||||||
|
56: 'Diamond ore',
|
||||||
|
57: 'Block of diamond',
|
||||||
|
58: 'Crafting table',
|
||||||
|
59: 'Seeds',
|
||||||
|
60: 'Farmland',
|
||||||
|
61: 'Furnace',
|
||||||
|
62: 'Burning furnace',
|
||||||
|
63: 'Sign',
|
||||||
|
64: 'Wooden door',
|
||||||
|
65: 'Ladders',
|
||||||
|
66: 'Rails',
|
||||||
|
67: 'Cobblestone stairs',
|
||||||
|
68: 'Wall sign',
|
||||||
|
69: 'Lever',
|
||||||
|
70: 'Stone pressure plate',
|
||||||
|
71: 'Iron door',
|
||||||
|
72: 'Wooden pressure plate',
|
||||||
|
73: 'Redstone ore',
|
||||||
|
74: 'Glowing redstone ore',
|
||||||
|
75: 'Redstone torch (off)',
|
||||||
|
76: 'Redstone torch (on)',
|
||||||
|
77: 'Stone button',
|
||||||
|
78: 'Snow',
|
||||||
|
79: 'Ice',
|
||||||
|
80: 'Snow block',
|
||||||
|
81: 'Cactus',
|
||||||
|
82: 'Clay block',
|
||||||
|
83: 'Sugar cane',
|
||||||
|
84: 'Jukebox',
|
||||||
|
85: 'Fence',
|
||||||
|
86: 'Pumpkin',
|
||||||
|
87: 'Netherrack',
|
||||||
|
88: 'Soul sand',
|
||||||
|
89: 'Glowstone block',
|
||||||
|
90: 'Portal',
|
||||||
|
91: 'Jack-O-Lantern',
|
||||||
|
92: 'Cake',
|
||||||
|
93: 'Redstone repeater (off)',
|
||||||
|
94: 'Redstone repeater (on)',
|
||||||
|
95: 'Locked',
|
||||||
|
96: 'Trapdoor',
|
||||||
|
256: 'Iron shovel',
|
||||||
|
257: 'Iron pickaxe',
|
||||||
|
258: 'Iron axe',
|
||||||
|
259: 'Flint and steel',
|
||||||
|
260: 'Red apple',
|
||||||
|
261: 'Bow',
|
||||||
|
262: 'Arrow',
|
||||||
|
263: 'Coal',
|
||||||
|
264: 'Diamond',
|
||||||
|
265: 'Iron ingot',
|
||||||
|
266: 'Gold ingot',
|
||||||
|
267: 'Iron sword',
|
||||||
|
268: 'Wooden sword',
|
||||||
|
269: 'Wooden shovel',
|
||||||
|
270: 'Wooden pickaxe',
|
||||||
|
271: 'Wooden axe',
|
||||||
|
272: 'Stone sword',
|
||||||
|
273: 'Stone shovel',
|
||||||
|
274: 'Stone pickaxe',
|
||||||
|
275: 'Stone axe',
|
||||||
|
276: 'Diamond sword',
|
||||||
|
277: 'Diamond shovel',
|
||||||
|
278: 'Diamond pickaxe',
|
||||||
|
279: 'Diamond axe',
|
||||||
|
280: 'Stick',
|
||||||
|
281: 'Bowl',
|
||||||
|
282: 'Mushroom soup',
|
||||||
|
283: 'Gold sword',
|
||||||
|
284: 'Gold shovel',
|
||||||
|
285: 'Gold pickaxe',
|
||||||
|
286: 'Gold axe',
|
||||||
|
287: 'String',
|
||||||
|
288: 'Feather',
|
||||||
|
289: 'Gunpowder',
|
||||||
|
290: 'Wooden hoe',
|
||||||
|
291: 'Stone hoe',
|
||||||
|
292: 'Iron hoe',
|
||||||
|
293: 'Diamond hoe',
|
||||||
|
294: 'Gold hoe',
|
||||||
|
295: 'Seeds',
|
||||||
|
296: 'Wheat',
|
||||||
|
297: 'Bread',
|
||||||
|
298: 'Leather cap',
|
||||||
|
299: 'Leather tunic',
|
||||||
|
300: 'Leather pants',
|
||||||
|
301: 'Leather boots',
|
||||||
|
302: 'Chain helmet',
|
||||||
|
303: 'Chain chestplate',
|
||||||
|
304: 'Chain leggings',
|
||||||
|
305: 'Chain boots',
|
||||||
|
306: 'Iron helmet',
|
||||||
|
307: 'Iron chestplate',
|
||||||
|
308: 'Iron leggings',
|
||||||
|
309: 'Iron boots',
|
||||||
|
310: 'Diamond helmet',
|
||||||
|
311: 'Diamond chestplate',
|
||||||
|
312: 'Diamond leggings',
|
||||||
|
313: 'Diamond boots',
|
||||||
|
314: 'Gold helmet',
|
||||||
|
315: 'Gold chestplate',
|
||||||
|
316: 'Gold leggings',
|
||||||
|
317: 'Gold boots',
|
||||||
|
318: 'Flint',
|
||||||
|
319: 'Raw porkchop',
|
||||||
|
320: 'Cooked porkchop',
|
||||||
|
321: 'Paintings',
|
||||||
|
322: 'Golden apple',
|
||||||
|
323: 'Sign',
|
||||||
|
324: 'Wooden door',
|
||||||
|
325: 'Bucket',
|
||||||
|
326: 'Water bucket',
|
||||||
|
327: 'Lava bucket',
|
||||||
|
328: 'Minecart',
|
||||||
|
329: 'Saddle',
|
||||||
|
330: 'Iron door',
|
||||||
|
331: 'Redstone',
|
||||||
|
332: 'Snowball',
|
||||||
|
333: 'Boat',
|
||||||
|
334: 'Leather',
|
||||||
|
335: 'Milk',
|
||||||
|
336: 'Clay brick',
|
||||||
|
337: 'Clay',
|
||||||
|
338: 'Sugar cane',
|
||||||
|
339: 'Paper',
|
||||||
|
340: 'Book',
|
||||||
|
341: 'Slimeball',
|
||||||
|
342: 'Minecart with chest',
|
||||||
|
343: 'Minecart with furnace',
|
||||||
|
344: 'Egg',
|
||||||
|
345: 'Compass',
|
||||||
|
346: 'Fishing rod',
|
||||||
|
347: 'Clock',
|
||||||
|
348: 'Glowstone dust',
|
||||||
|
349: 'Raw fish',
|
||||||
|
350: 'Cooked fish',
|
||||||
|
351: 'Dye',
|
||||||
|
352: 'Bone',
|
||||||
|
353: 'Sugar',
|
||||||
|
354: 'Cake',
|
||||||
|
355: 'Bed',
|
||||||
|
356: 'Redstone repeater',
|
||||||
|
357: 'Cookie',
|
||||||
|
358: 'Map',
|
||||||
|
359: 'Shears',
|
||||||
|
2256: 'Gold music disc',
|
||||||
|
2257: 'Green music disc'
|
||||||
|
}
|
||||||
|
|
||||||
|
def id2item(item_id):
|
||||||
|
if item_id in items:
|
||||||
|
return items[item_id]
|
||||||
|
else:
|
||||||
|
return item_id
|
||||||
@@ -17,6 +17,7 @@ import gzip, zlib
|
|||||||
import struct
|
import struct
|
||||||
import StringIO
|
import StringIO
|
||||||
import os
|
import os
|
||||||
|
import numpy
|
||||||
|
|
||||||
# decorator to handle filename or object as first parameter
|
# decorator to handle filename or object as first parameter
|
||||||
def _file_loader(func):
|
def _file_loader(func):
|
||||||
@@ -34,15 +35,15 @@ def _file_loader(func):
|
|||||||
def load(fileobj):
|
def load(fileobj):
|
||||||
return NBTFileReader(fileobj).read_all()
|
return NBTFileReader(fileobj).read_all()
|
||||||
|
|
||||||
def load_from_region(filename, x, y):
|
def load_from_region(filename, x, y, north_direction):
|
||||||
nbt = load_region(filename).load_chunk(x, y)
|
nbt = load_region(filename, north_direction).load_chunk(x, y)
|
||||||
if nbt is None:
|
if nbt is None:
|
||||||
return None ## return none. I think this is who we should indicate missing chunks
|
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))
|
#raise IOError("No such chunk in region: (%i, %i)" % (x, y))
|
||||||
return nbt.read_all()
|
return nbt.read_all()
|
||||||
|
|
||||||
def load_region(filename):
|
def load_region(filename, north_direction):
|
||||||
return MCRFileReader(filename)
|
return MCRFileReader(filename, north_direction)
|
||||||
|
|
||||||
|
|
||||||
# compile the unpacker's into a classes
|
# compile the unpacker's into a classes
|
||||||
@@ -199,13 +200,24 @@ class MCRFileReader(object):
|
|||||||
chunks (as instances of NBTFileReader), getting chunk timestamps,
|
chunks (as instances of NBTFileReader), getting chunk timestamps,
|
||||||
and for listing chunks contained in the file."""
|
and for listing chunks contained in the file."""
|
||||||
|
|
||||||
def __init__(self, filename):
|
def __init__(self, filename, north_direction):
|
||||||
self._file = None
|
self._file = None
|
||||||
self._filename = filename
|
self._filename = filename
|
||||||
|
self.north_direction = north_direction
|
||||||
# cache used when the entire header tables are read in get_chunks()
|
# cache used when the entire header tables are read in get_chunks()
|
||||||
self._locations = None
|
self._locations = None
|
||||||
self._timestamps = None
|
self._timestamps = None
|
||||||
self._chunks = 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):
|
def _read_24bit_int(self):
|
||||||
"""Read in a 24-bit, big-endian int, used in the chunk
|
"""Read in a 24-bit, big-endian int, used in the chunk
|
||||||
@@ -318,21 +330,24 @@ class MCRFileReader(object):
|
|||||||
self.openfile()
|
self.openfile()
|
||||||
|
|
||||||
self._chunks = None
|
self._chunks = None
|
||||||
self._locations = []
|
self._locations = [0]*32*32
|
||||||
self._timestamps = []
|
self._timestamps = []
|
||||||
|
|
||||||
# go to the beginning of the file
|
# go to the beginning of the file
|
||||||
self._file.seek(0)
|
self._file.seek(0)
|
||||||
|
|
||||||
# read chunk location table
|
# read chunk location table
|
||||||
locations_append = self._locations.append
|
locations_index = numpy.reshape(numpy.rot90(numpy.reshape(range(32*32),
|
||||||
for _ in xrange(32*32):
|
(32, 32)), -self.get_north_rotations()), -1)
|
||||||
locations_append(self._read_chunk_location())
|
for i in locations_index:
|
||||||
|
self._locations[i] = self._read_chunk_location()
|
||||||
|
|
||||||
# read chunk timestamp table
|
# read chunk timestamp table
|
||||||
timestamp_append = self._timestamps.append
|
timestamp_append = self._timestamps.append
|
||||||
for _ in xrange(32*32):
|
for _ in xrange(32*32):
|
||||||
timestamp_append(self._read_chunk_timestamp())
|
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:
|
if closeFile:
|
||||||
self.closefile()
|
self.closefile()
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ class QuadtreeGen(object):
|
|||||||
tile_mtime = None
|
tile_mtime = None
|
||||||
|
|
||||||
#check mtimes on each part of the quad, this also checks if they exist
|
#check mtimes on each part of the quad, this also checks if they exist
|
||||||
needs_rerender = tile_mtime is None
|
needs_rerender = (tile_mtime is None) or self.forcerender
|
||||||
quadPath_filtered = []
|
quadPath_filtered = []
|
||||||
for path in quadPath:
|
for path in quadPath:
|
||||||
try:
|
try:
|
||||||
@@ -318,7 +318,7 @@ class QuadtreeGen(object):
|
|||||||
if tile_mtime is not None:
|
if tile_mtime is not None:
|
||||||
os.unlink(imgpath)
|
os.unlink(imgpath)
|
||||||
return
|
return
|
||||||
# quit now if we don't need rerender
|
# quit now if we don't need rerender
|
||||||
if not needs_rerender:
|
if not needs_rerender:
|
||||||
return
|
return
|
||||||
#logging.debug("writing out innertile {0}".format(imgpath))
|
#logging.debug("writing out innertile {0}".format(imgpath))
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ def pool_initializer(rendernode):
|
|||||||
|
|
||||||
# make sure textures are generated for this process
|
# make sure textures are generated for this process
|
||||||
# and initialize c_overviewer
|
# 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()
|
c_overviewer.init_chunk_render()
|
||||||
|
|
||||||
# load biome data in each process, if needed
|
# load biome data in each process, if needed
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ alpha_over_full(PyObject *dest, PyObject *src, PyObject *mask, float overall_alp
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* special cases */
|
/* special cases */
|
||||||
if (in_alpha == 255 || *outmask == 0) {
|
if (in_alpha == 255 || (*outmask == 0 && in_alpha > 0)) {
|
||||||
*outmask = in_alpha;
|
*outmask = in_alpha;
|
||||||
|
|
||||||
*out = *in;
|
*out = *in;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
// increment this value if you've made a change to the c extesion
|
// increment this value if you've made a change to the c extesion
|
||||||
// and want to force users to rebuild
|
// and want to force users to rebuild
|
||||||
#define OVERVIEWER_EXTENSION_VERSION 8
|
#define OVERVIEWER_EXTENSION_VERSION 10
|
||||||
|
|
||||||
/* Python PIL, and numpy headers */
|
/* Python PIL, and numpy headers */
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|||||||
@@ -185,9 +185,14 @@ get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
|||||||
|
|
||||||
/* stairs and half-blocks take the skylevel from the upper block if it's transparent */
|
/* stairs and half-blocks take the skylevel from the upper block if it's transparent */
|
||||||
if (local_z != 127) {
|
if (local_z != 127) {
|
||||||
upper_block = getArrayByte3D(blocks, local_x, local_y, local_z + 1);
|
int upper_counter = 0;
|
||||||
|
/* but if the upper_block is one of these special half-steps, we need to look at *its* upper_block */
|
||||||
|
do {
|
||||||
|
upper_counter++;
|
||||||
|
upper_block = getArrayByte3D(blocks, local_x, local_y, local_z + upper_counter);
|
||||||
|
} while ((upper_block == 44 || upper_block == 54 || upper_block == 67) && local_z < 127);
|
||||||
if (is_transparent(upper_block)) {
|
if (is_transparent(upper_block)) {
|
||||||
skylevel = getArrayByte3D(skylight, local_x, local_y, local_z + 1);
|
skylevel = getArrayByte3D(skylight, local_x, local_y, local_z + upper_counter);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
upper_block = 0;
|
upper_block = 0;
|
||||||
@@ -195,7 +200,7 @@ get_lighting_coefficient(RenderModeLighting *self, RenderState *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* the block has a bad blocklevel, estimate it from neigborhood
|
/* the block has a bad blocklevel, estimate it from neigborhood
|
||||||
/* use given coordinates, no local ones! */
|
* use given coordinates, no local ones! */
|
||||||
blocklevel = estimate_blocklevel(self, state, x, y, z, NULL);
|
blocklevel = estimate_blocklevel(self, state, x, y, z, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -513,6 +513,9 @@ def generate_texture_tuple(img, blockid):
|
|||||||
|
|
||||||
def generate_special_texture(blockID, data):
|
def generate_special_texture(blockID, data):
|
||||||
"""Generates a special texture, such as a correctly facing minecraft track"""
|
"""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)
|
# blocks need to be handled here (and in chunk.py)
|
||||||
|
|
||||||
if blockID == 2: # grass
|
if blockID == 2: # grass
|
||||||
@@ -1679,6 +1682,237 @@ def generate_special_texture(blockID, data):
|
|||||||
|
|
||||||
return None
|
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):
|
def tintTexture(im, c):
|
||||||
# apparently converting to grayscale drops the alpha channel?
|
# apparently converting to grayscale drops the alpha channel?
|
||||||
i = ImageOps.colorize(ImageOps.grayscale(im), (0,0,0), c)
|
i = ImageOps.colorize(ImageOps.grayscale(im), (0,0,0), c)
|
||||||
@@ -1722,8 +1956,25 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
global currentBiomeFile, currentBiomeData
|
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:
|
if biomeFile == currentBiomeFile:
|
||||||
return currentBiomeData
|
return currentBiomeData
|
||||||
|
|
||||||
@@ -1733,7 +1984,9 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
|||||||
# make sure the file size is correct
|
# make sure the file size is correct
|
||||||
if not len(rawdata) == 512 * 512 * 2:
|
if not len(rawdata) == 512 * 512 * 2:
|
||||||
raise Exception("Biome file %s is not valid." % (biomeFile,))
|
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:
|
except IOError:
|
||||||
data = None
|
data = None
|
||||||
pass # no biome data
|
pass # no biome data
|
||||||
@@ -1822,7 +2075,10 @@ biome_tall_fern_texture = None
|
|||||||
biome_leaf_texture = None
|
biome_leaf_texture = None
|
||||||
specialblockmap = 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
|
global bgcolor
|
||||||
bgcolor = bgc
|
bgcolor = bgc
|
||||||
global _find_file_local_path, texture_dimensions
|
global _find_file_local_path, texture_dimensions
|
||||||
|
|||||||
@@ -69,11 +69,70 @@ class World(object):
|
|||||||
|
|
||||||
mincol = maxcol = minrow = maxrow = 0
|
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="auto"):
|
||||||
self.worlddir = worlddir
|
self.worlddir = worlddir
|
||||||
self.outputdir = outputdir
|
self.outputdir = outputdir
|
||||||
self.useBiomeData = useBiomeData
|
self.useBiomeData = useBiomeData
|
||||||
|
self.north_direction = north_direction
|
||||||
|
|
||||||
|
# figure out chunk format is in use
|
||||||
|
# if not mcregion, error out early
|
||||||
|
data = nbt.load(os.path.join(self.worlddir, "level.dat"))[1]['Data']
|
||||||
|
#print data
|
||||||
|
if not ('version' in data and data['version'] == 19132):
|
||||||
|
logging.error("Sorry, This version of Minecraft-Overviewer only works with the new McRegion chunk format")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# stores Points Of Interest to be mapped with markers
|
||||||
|
# a list of dictionaries, see below for an example
|
||||||
|
self.POI = []
|
||||||
|
|
||||||
|
# if it exists, open overviewer.dat, and read in the data structure
|
||||||
|
# info self.persistentData. This dictionary can hold any information
|
||||||
|
# that may be needed between runs.
|
||||||
|
# Currently only holds into about POIs (more more details, see quadtree)
|
||||||
|
|
||||||
|
self.oldPickleFile = os.path.join(self.worlddir, "overviewer.dat")
|
||||||
|
self.pickleFile = os.path.join(self.outputdir, "overviewer.dat")
|
||||||
|
|
||||||
|
if os.path.exists(self.oldPickleFile):
|
||||||
|
logging.warning("overviewer.dat detected in WorldDir - this is no longer the correct location")
|
||||||
|
if os.path.exists(self.pickleFile):
|
||||||
|
# new file exists, so make a note of it
|
||||||
|
logging.warning("you should delete the `overviewer.dat' file in your world directory")
|
||||||
|
else:
|
||||||
|
# new file does not exist, so move the old one
|
||||||
|
logging.warning("Moving overviewer.dat to OutputDir")
|
||||||
|
import shutil
|
||||||
|
try:
|
||||||
|
# make sure destination dir actually exists
|
||||||
|
try:
|
||||||
|
os.mkdir(self.outputdir)
|
||||||
|
except OSError: # already exists, or failed
|
||||||
|
pass
|
||||||
|
shutil.move(self.oldPickleFile, self.pickleFile)
|
||||||
|
logging.info("overviewer.dat moved")
|
||||||
|
except BaseException as ex:
|
||||||
|
logging.error("Unable to move overviewer.dat")
|
||||||
|
logging.debug(ex.str())
|
||||||
|
|
||||||
|
if os.path.exists(self.pickleFile):
|
||||||
|
self.persistentDataIsNew = False;
|
||||||
|
with open(self.pickleFile,"rb") as p:
|
||||||
|
self.persistentData = cPickle.load(p)
|
||||||
|
if not self.persistentData.get('north_direction', False):
|
||||||
|
# this is a pre-configurable-north map, so add the north_direction key
|
||||||
|
self.persistentData['north_direction'] = 'lower-left'
|
||||||
|
else:
|
||||||
|
# some defaults, presumably a new map
|
||||||
|
self.persistentData = dict(POI=[], north_direction='lower-left')
|
||||||
|
self.persistentDataIsNew = True # indicates that the values in persistentData are new defaults, and it's OK to override them
|
||||||
|
|
||||||
|
# handle 'auto' north
|
||||||
|
if self.north_direction == 'auto':
|
||||||
|
self.north_direction = self.persistentData['north_direction']
|
||||||
|
north_direction = self.north_direction
|
||||||
|
|
||||||
#find region files, or load the region list
|
#find region files, or load the region list
|
||||||
#this also caches all the region file header info
|
#this also caches all the region file header info
|
||||||
logging.info("Scanning regions")
|
logging.info("Scanning regions")
|
||||||
@@ -96,43 +155,6 @@ class World(object):
|
|||||||
self.empty_chunk = [None,None]
|
self.empty_chunk = [None,None]
|
||||||
logging.debug("Done scanning regions")
|
logging.debug("Done scanning regions")
|
||||||
|
|
||||||
# figure out chunk format is in use
|
|
||||||
# if not mcregion, error out early
|
|
||||||
data = nbt.load(os.path.join(self.worlddir, "level.dat"))[1]['Data']
|
|
||||||
#print data
|
|
||||||
if not ('version' in data and data['version'] == 19132):
|
|
||||||
logging.error("Sorry, This version of Minecraft-Overviewer only works with the new McRegion chunk format")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# stores Points Of Interest to be mapped with markers
|
|
||||||
# a list of dictionaries, see below for an example
|
|
||||||
self.POI = []
|
|
||||||
|
|
||||||
# if it exists, open overviewer.dat, and read in the data structure
|
|
||||||
# info self.persistentData. This dictionary can hold any information
|
|
||||||
# that may be needed between runs.
|
|
||||||
# Currently only holds into about POIs (more more details, see quadtree)
|
|
||||||
|
|
||||||
self.pickleFile = os.path.join(self.worlddir, "overviewer.dat")
|
|
||||||
if os.path.exists(self.pickleFile):
|
|
||||||
logging.warning("overviewer.dat detected in WorldDir - this is no longer the correct location")
|
|
||||||
logging.warning("Moving overviewer.dat to OutputDir")
|
|
||||||
import shutil
|
|
||||||
try:
|
|
||||||
shutil.move(self.pickleFile, self.outputdir)
|
|
||||||
logging.info("overviewer.dat moved")
|
|
||||||
except BaseException as ex:
|
|
||||||
logging.error("Unable to move overviewer.dat")
|
|
||||||
logging.debug(ex.str())
|
|
||||||
|
|
||||||
self.pickleFile = os.path.join(self.outputdir, "overviewer.dat")
|
|
||||||
if os.path.exists(self.pickleFile):
|
|
||||||
with open(self.pickleFile,"rb") as p:
|
|
||||||
self.persistentData = cPickle.load(p)
|
|
||||||
else:
|
|
||||||
# some defaults
|
|
||||||
self.persistentData = dict(POI=[])
|
|
||||||
|
|
||||||
|
|
||||||
def get_region_path(self, chunkX, chunkY):
|
def get_region_path(self, chunkX, chunkY):
|
||||||
"""Returns the path to the region that contains chunk (chunkX, chunkY)
|
"""Returns the path to the region that contains chunk (chunkX, chunkY)
|
||||||
@@ -164,6 +186,18 @@ class World(object):
|
|||||||
data = nbt.read_all()
|
data = nbt.read_all()
|
||||||
level = data[1]['Level']
|
level = data[1]['Level']
|
||||||
chunk_data = 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 = {}
|
||||||
#chunk_data['skylight'] = chunk.get_skylight_array(level)
|
#chunk_data['skylight'] = chunk.get_skylight_array(level)
|
||||||
#chunk_data['blocklight'] = chunk.get_blocklight_array(level)
|
#chunk_data['blocklight'] = chunk.get_blocklight_array(level)
|
||||||
@@ -180,7 +214,7 @@ class World(object):
|
|||||||
if self.regions.get(filename) is not None:
|
if self.regions.get(filename) is not None:
|
||||||
self.regions[filename][0].closefile()
|
self.regions[filename][0].closefile()
|
||||||
chunkcache = {}
|
chunkcache = {}
|
||||||
mcr = nbt.MCRFileReader(filename)
|
mcr = nbt.MCRFileReader(filename, self.north_direction)
|
||||||
self.regions[filename] = (mcr,os.path.getmtime(filename),chunkcache)
|
self.regions[filename] = (mcr,os.path.getmtime(filename),chunkcache)
|
||||||
return mcr
|
return mcr
|
||||||
|
|
||||||
@@ -196,7 +230,7 @@ class World(object):
|
|||||||
in the image each one should be. Returns (col, row)."""
|
in the image each one should be. Returns (col, row)."""
|
||||||
|
|
||||||
# columns are determined by the sum of the chunk coords, rows are the
|
# 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
|
# change this function, and you MUST change unconvert_coords
|
||||||
return (chunkx + chunky, chunky - chunkx)
|
return (chunkx + chunky, chunky - chunkx)
|
||||||
|
|
||||||
@@ -214,9 +248,20 @@ class World(object):
|
|||||||
|
|
||||||
## read spawn info from level.dat
|
## read spawn info from level.dat
|
||||||
data = nbt.load(os.path.join(self.worlddir, "level.dat"))[1]
|
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']
|
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
|
## The chunk that holds the spawn location
|
||||||
chunkX = spawnX/16
|
chunkX = spawnX/16
|
||||||
@@ -226,7 +271,7 @@ class World(object):
|
|||||||
## The filename of this chunk
|
## The filename of this chunk
|
||||||
chunkFile = self.get_region_path(chunkX, chunkY)
|
chunkFile = self.get_region_path(chunkX, chunkY)
|
||||||
if chunkFile is not None:
|
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:
|
if data is not None:
|
||||||
level = data['Level']
|
level = data['Level']
|
||||||
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
||||||
@@ -243,9 +288,9 @@ class World(object):
|
|||||||
except ChunkCorrupt:
|
except ChunkCorrupt:
|
||||||
#ignore corrupt spawn, and continue
|
#ignore corrupt spawn, and continue
|
||||||
pass
|
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)))
|
msg="Spawn", type="spawn", chunk=(chunkX, chunkY)))
|
||||||
self.spawn = (spawnX, spawnY, spawnZ)
|
self.spawn = (disp_spawnX, spawnY, disp_spawnZ)
|
||||||
|
|
||||||
def go(self, procs):
|
def go(self, procs):
|
||||||
"""Scan the world directory, to fill in
|
"""Scan the world directory, to fill in
|
||||||
@@ -291,6 +336,16 @@ class World(object):
|
|||||||
|
|
||||||
self.findTrueSpawn()
|
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):
|
def _iterate_regionfiles(self,regionlist=None):
|
||||||
"""Returns an iterator of all of the region files, along with their
|
"""Returns an iterator of all of the region files, along with their
|
||||||
coordinates
|
coordinates
|
||||||
@@ -307,7 +362,20 @@ class World(object):
|
|||||||
if f.startswith("r.") and f.endswith(".mcr"):
|
if f.startswith("r.") and f.endswith(".mcr"):
|
||||||
p = f.split(".")
|
p = f.split(".")
|
||||||
logging.debug("Using path %s from regionlist", f)
|
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:
|
else:
|
||||||
logging.warning("Ignore path '%s' in regionlist", f)
|
logging.warning("Ignore path '%s' in regionlist", f)
|
||||||
|
|
||||||
@@ -315,7 +383,20 @@ class World(object):
|
|||||||
for path in glob(os.path.join(self.worlddir, 'region') + "/r.*.*.mcr"):
|
for path in glob(os.path.join(self.worlddir, 'region') + "/r.*.*.mcr"):
|
||||||
dirpath, f = os.path.split(path)
|
dirpath, f = os.path.split(path)
|
||||||
p = f.split(".")
|
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():
|
def get_save_dir():
|
||||||
"""Returns the path to the local saves directory
|
"""Returns the path to the local saves directory
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ if procs < 1: procs = 1
|
|||||||
## Sets the zoom level manually instead of calculating it. This can be useful
|
## Sets the zoom level manually instead of calculating it. This can be useful
|
||||||
## if you have outlier chunks that make your world too big. This value will
|
## if you have outlier chunks that make your world too big. This value will
|
||||||
## make the highest zoom level contain (2**ZOOM)^2 tiles
|
## make the highest zoom level contain (2**ZOOM)^2 tiles
|
||||||
## Normally you should not need to set this variable.
|
## ***Normally you should not need to set this variable.***
|
||||||
|
## ***Setting it too low will crop your map!***
|
||||||
|
## Seriously, check the README before using this.
|
||||||
## Default: Automatically calculated from your world
|
## Default: Automatically calculated from your world
|
||||||
## Type: integer
|
## Type: integer
|
||||||
## Example:
|
## Example:
|
||||||
@@ -152,10 +154,19 @@ verbose = 1
|
|||||||
if "web_assets_hook" in locals():
|
if "web_assets_hook" in locals():
|
||||||
skipjs = True
|
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"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### As a reminder, don't use this file verbatim, it should only be used as
|
### As a reminder, *don't use this file verbatim*, it should only be used as
|
||||||
### a guide.
|
### a guide. Be sure to read what each option does before you set it.
|
||||||
|
### See the README for more details.
|
||||||
import sys
|
import sys
|
||||||
sys.exit("This sample-settings file shouldn't be used directly!")
|
sys.exit("This sample-settings file shouldn't be used directly!")
|
||||||
|
|||||||
4
setup.py
4
setup.py
@@ -91,6 +91,10 @@ def recursive_package_data(src, package_dir='overviewer_core'):
|
|||||||
#
|
#
|
||||||
|
|
||||||
if py2exe is not None:
|
if py2exe is not None:
|
||||||
|
setup_kwargs['comments'] = "http://overviewer.org"
|
||||||
|
# py2exe likes a very particular type of version number:
|
||||||
|
setup_kwargs['version'] = util.findGitVersion().replace("-",".")
|
||||||
|
|
||||||
setup_kwargs['console'] = ['overviewer.py', 'contribManager.py']
|
setup_kwargs['console'] = ['overviewer.py', 'contribManager.py']
|
||||||
setup_kwargs['data_files'] = [('', doc_files)]
|
setup_kwargs['data_files'] = [('', doc_files)]
|
||||||
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/textures', 'textures')
|
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/textures', 'textures')
|
||||||
|
|||||||
Reference in New Issue
Block a user