0

Merge branch 'master' into rendermode-options

Conflicts:
	overviewer_core/chunk.py
	overviewer_core/src/iterate.c
This commit is contained in:
Aaron Griffith
2011-07-31 22:46:19 -04:00
13 changed files with 428 additions and 210 deletions

View File

@@ -41,6 +41,7 @@ feature.
* arrai <array.of.intellect@gmail.com> * arrai <array.of.intellect@gmail.com>
* Kyle Brantley <kyle@averageurl.com> * Kyle Brantley <kyle@averageurl.com>
* but2002 <barryt_9@hotmail.com>
* Eric Carr <eric@carr.no> * Eric Carr <eric@carr.no>
* cbarber <CraigBarber@taryx.com> * cbarber <CraigBarber@taryx.com>
* Alex Cline <cline@vivisimo.com> * Alex Cline <cline@vivisimo.com>

View File

@@ -4,6 +4,6 @@ include CONTRIBUTORS.rst
include overviewer.py include overviewer.py
include sample.settings.py include sample.settings.py
recursive-include contrib/ *.py recursive-include contrib/ *.py
recursive-include overviewer_core/*.py recursive-include overviewer_core/ *.py
recursive-include overviewer_core/src/ *.c *.h recursive-include overviewer_core/src/ *.c *.h
recursive-include overviewer_core/data/ *.png *.js index.html style.css recursive-include overviewer_core/data/ *

View File

@@ -188,6 +188,11 @@ def main():
parser.print_help() parser.print_help()
logging.error("Invalid world number") logging.error("Invalid world number")
sys.exit(1) sys.exit(1)
# final sanity check for worlddir
if not os.path.exists(os.path.join(worlddir, 'level.dat')):
logging.error("Invalid world path -- does not contain level.dat")
sys.exit(1)
if len(args) < 2: if len(args) < 2:
if options.delete: if options.delete:

View File

@@ -114,10 +114,10 @@ def get_tileentity_data(level):
return data return data
# This set holds blocks ids that can be seen through, for occlusion calculations # This set holds blocks ids that can be seen through, for occlusion calculations
transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 30, 31, 32, 37, 38, transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 29, 30, 31, 32, 33,
39, 40, 44, 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67, 34, 37, 38, 39, 40, 44, 50, 51, 52, 53, 55, 59, 63, 64,
68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79,
90, 92, 93, 94, 96]) 81, 83, 85, 90, 92, 93, 94, 96])
# This set holds block ids that are solid blocks # This set holds block ids that are solid blocks
solid_blocks = set([1, 2, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, solid_blocks = set([1, 2, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
@@ -335,67 +335,6 @@ class ChunkRenderer(object):
return self._up_left_blocklight return self._up_left_blocklight
up_left_blocklight = property(_load_up_left_blocklight) up_left_blocklight = property(_load_up_left_blocklight)
def generate_pseudo_ancildata(self,x,y,z,blockid, north_position = 0 ):
""" Generates a pseudo ancillary data for blocks that depend of
what are surrounded and don't have ancillary data
This uses a binary number of 4 digits to encode the info.
The encode is:
Bit: 1 2 3 4
Side: x y -x -y
Values: bit = 0 -> The corresponding side block has different blockid
bit = 1 -> The corresponding side block has same blockid
Example: if the bit1 is 1 that means that there is a block with
blockid in the side of the +x direction.
You can rotate the pseudo data multiplying by 2 and
if it is > 15 subtracting 15 and adding 1. (moving bits
in the left direction is like rotate 90 degree in anticlockwise
direction). In this way can be used for maps with other
north orientation.
North position can have the values 0, 1, 2, 3, corresponding to
north in bottom-left, bottom-right, top-right and top-left of
the screen.
The rotation feature is not used anywhere yet.
"""
blocks = self.blocks
up_left_blocks = self.up_left_blocks
up_right_blocks = self.up_right_blocks
left_blocks = self.left_blocks
right_blocks = self.right_blocks
pseudo_data = 0
# first check if we are in the border of a chunk, next check for chunks adjacent to this
# and finally check for a block with same blockid. I we aren't in the border of a chunk,
# check for the block having the sme blockid.
if (up_right_blocks is not None and up_right_blocks[0,y,z] == blockid) if x == 15 else blocks[x+1,y,z] == blockid:
pseudo_data = pseudo_data | 0b1000
if (right_blocks is not None and right_blocks[x,0,z] == blockid) if y == 15 else blocks[x,y + 1,z] == blockid:
pseudo_data = pseudo_data | 0b0100
if (left_blocks is not None and left_blocks[15,y,z] == blockid) if x == 0 else blocks[x - 1,y,z] == blockid:
pseudo_data = pseudo_data | 0b0010
if (up_left_blocks is not None and up_left_blocks[x,15,z] == blockid) if y == 0 else blocks[x,y - 1,z] == blockid:
pseudo_data = pseudo_data | 0b0001
# rotate the bits for other north orientations
while north_position > 0:
pseudo_data *= 2
if pseudo_data > 15:
pseudo_data -= 16
pseudo_data +=1
north_position -= 1
return pseudo_data
def chunk_render(self, img=None, xoff=0, yoff=0, cave=False): def chunk_render(self, img=None, xoff=0, yoff=0, cave=False):
"""Renders a chunk with the given parameters, and returns the image. """Renders a chunk with the given parameters, and returns the image.
If img is given, the chunk is rendered to that image object. Otherwise, If img is given, the chunk is rendered to that image object. Otherwise,

View File

@@ -58,7 +58,6 @@ var overviewer = {
overviewer.util.initializeMarkers(); overviewer.util.initializeMarkers();
overviewer.util.initializeRegions(); overviewer.util.initializeRegions();
overviewer.util.createMapControls(); overviewer.util.createMapControls();
overviewer.util.createSearchBox();
}, },
/** /**
* This adds some methods to these classes because Javascript is stupid * This adds some methods to these classes because Javascript is stupid
@@ -166,6 +165,9 @@ var overviewer = {
var zoom = overviewerConfig.map.defaultZoom; var zoom = overviewerConfig.map.defaultZoom;
var mapcenter; var mapcenter;
var queryParams = overviewer.util.parseQueryString(); var queryParams = overviewer.util.parseQueryString();
if (queryParams.debug) {
overviewerConfig.map.debug=true;
}
if (queryParams.lat) { if (queryParams.lat) {
lat = parseFloat(queryParams.lat); lat = parseFloat(queryParams.lat);
} }
@@ -311,6 +313,9 @@ var overviewer = {
'title': jQuery.trim(item.msg), 'title': jQuery.trim(item.msg),
'icon': overviewerConfig.CONST.image.queryMarker 'icon': overviewerConfig.CONST.image.queryMarker
}); });
google.maps.event.addListener(marker, 'click', function(){ marker.setVisible(false); });
continue; continue;
} }
@@ -392,59 +397,76 @@ var overviewer = {
point.x, point.y, point.z)); point.x, point.y, point.z));
} }
if (region.label) {
var name = region.label;
} else {
var name = "rawr";
}
if(region.opacity) {
var strokeOpacity = region.opacity;
var fillOpacity = region.opacity * 0.25;
} else {
var strokeOpacity = region.strokeOpacity;
var fillOpacity = region.fillOpacity;
}
var shapeOptions = {
'name': name,
'geodesic': false,
'map': null,
'strokeColor': region.color,
'strokeOpacity': strokeOpacity,
'strokeWeight': overviewerConfig.CONST.regionStrokeWeight,
'zIndex': j
};
if (region.closed) {
shapeOptions["fillColor"] = region.color;
shapeOptions["fillOpacity"] = fillOpacity;
shapeOptions["paths"] = converted;
} else {
shapeOptions["path"] = converted;
}
var matched = false;
for (k in overviewerConfig.objectGroups.regions) { for (k in overviewerConfig.objectGroups.regions) {
var regionGroup = overviewerConfig.objectGroups.regions[k]; var regionGroup = overviewerConfig.objectGroups.regions[k];
var clickable = regionGroup.clickable; var clickable = regionGroup.clickable;
var label = regionGroup.label; var label = regionGroup.label;
if(region.label) { if (!regionGroup.match(region))
var name = region.label continue;
} else { matched = true;
var name = 'rawr';
if (!region.label) {
clickable = false; // if it doesn't have a name, we dont have to show it. clickable = false; // if it doesn't have a name, we dont have to show it.
} }
if(region.opacity) { if (region.closed) {
var strokeOpacity = region.opacity; var shape = new google.maps.Polygon(shapeOptions);
var fillOpacity = region.opacity * 0.25;
} else { } else {
var strokeOpacity = region.strokeOpacity; var shape = new google.maps.Polyline(shapeOptions);
var fillOpacity = region.fillOpacity;
} }
if (region.closed) {
var shape = new google.maps.Polygon({
'name': name,
'clickable': clickable,
'geodesic': false,
'map': null,
'strokeColor': region.color,
'strokeOpacity': strokeOpacity,
'strokeWeight': overviewerConfig.CONST.regionStrokeWeight,
'fillColor': region.color,
'fillOpacity': fillOpacity,
'zIndex': j,
'paths': converted
});
} else {
var shape = new google.maps.Polyline({
'name': name,
'clickable': clickable,
'geodesic': false,
'map': null,
'strokeColor': region.color,
'strokeOpacity': strokeOpacity,
'strokeWeight': overviewerConfig.CONST.regionStrokeWeight,
'zIndex': j,
'path': converted
});
}
overviewer.collections.regions[label].push(shape); overviewer.collections.regions[label].push(shape);
if (clickable) { if (clickable) {
overviewer.util.createRegionInfoWindow(shape); overviewer.util.createRegionInfoWindow(shape);
} }
} }
// if we haven't matched anything, go ahead and add it
if (!matched) {
if (region.closed) {
var shape = new google.maps.Polygon(shapeOptions);
} else {
var shape = new google.maps.Polyline(shapeOptions);
}
shape.setMap(overviewer.map);
}
} }
} }
}, },
@@ -512,7 +534,7 @@ var overviewer = {
// the width and height of all the highest-zoom tiles combined, // the width and height of all the highest-zoom tiles combined,
// inverted // inverted
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize * var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
Math.pow(2, overviewerConfig.map.maxZoom)); Math.pow(2, overviewerConfig.map.zoomLevels));
// 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
@@ -520,13 +542,13 @@ var overviewer = {
// point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2) // point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2)
// so the Y coordinate is at 0.5, and the X is at 0.5 - // so the Y coordinate is at 0.5, and the X is at 0.5 -
// ((tileSize / 2) / (tileSize * 2^maxZoom)) // ((tileSize / 2) / (tileSize * 2^zoomLevels))
// or equivalently, 0.5 - (1 / 2^(maxZoom + 1)) // or equivalently, 0.5 - (1 / 2^(zoomLevels + 1))
var lng = 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.maxZoom + 1)); var lng = 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.zoomLevels + 1));
var lat = 0.5; var lat = 0.5;
// the following metrics mimic those in ChunkRenderer.chunk_render // the following metrics mimic those in
// in "chunk.py" or, equivalently, chunk_render in src/iterate.c // chunk_render in src/iterate.c
// each block on X axis adds 12px to x and subtracts 6px from y // each block on X axis adds 12px to x and subtracts 6px from y
lng += 12 * x * perPixel; lng += 12 * x * perPixel;
@@ -564,11 +586,11 @@ var overviewer = {
// the width and height of all the highest-zoom tiles combined, // the width and height of all the highest-zoom tiles combined,
// inverted // inverted
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize * var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
Math.pow(2, overviewerConfig.map.maxZoom)); Math.pow(2, overviewerConfig.map.zoomLevels));
// Revert base positioning // Revert base positioning
// See equivalent code in fromWorldToLatLng() // See equivalent code in fromWorldToLatLng()
lng -= 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.maxZoom + 1)); lng -= 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.zoomLevels + 1));
lat -= 0.5; lat -= 0.5;
// I'll admit, I plugged this into Wolfram Alpha: // I'll admit, I plugged this into Wolfram Alpha:
@@ -617,7 +639,10 @@ var overviewer = {
var coordsDiv = document.createElement('DIV'); var coordsDiv = document.createElement('DIV');
coordsDiv.id = 'coordsDiv'; coordsDiv.id = 'coordsDiv';
coordsDiv.innerHTML = ''; coordsDiv.innerHTML = '';
overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(coordsDiv); if (overviewerConfig.map.controls.coordsBox) {
overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(coordsDiv);
}
// Update coords on mousemove // Update coords on mousemove
google.maps.event.addListener(overviewer.map, 'mousemove', function (event) { google.maps.event.addListener(overviewer.map, 'mousemove', function (event) {
var worldcoords = overviewer.util.fromLatLngToWorld(event.latLng.lat(), event.latLng.lng()); var worldcoords = overviewer.util.fromLatLngToWorld(event.latLng.lat(), event.latLng.lng());
@@ -684,7 +709,7 @@ var overviewer = {
overviewer.util.createDropDown('Regions', items); overviewer.util.createDropDown('Regions', items);
} }
if (overviewer.collections.overlays.length > 0) { if (overviewerConfig.map.controls.overlays && overviewer.collections.overlays.length > 0) {
// overlay maps control // overlay maps control
var items = []; var items = [];
for (i in overviewer.collections.overlays) { for (i in overviewer.collections.overlays) {
@@ -712,6 +737,9 @@ var overviewer = {
} }
overviewer.util.createDropDown('Overlays', items); overviewer.util.createDropDown('Overlays', items);
} }
// call out to create search box, as it's pretty complicated
overviewer.util.createSearchBox();
}, },
/** /**
* Reusable method for creating drop-down menus * Reusable method for creating drop-down menus
@@ -832,8 +860,10 @@ var overviewer = {
$(searchDropDown).fadeOut(); $(searchDropDown).fadeOut();
} }
}); });
overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(searchControl); if (overviewerConfig.map.controls.searchBox) {
overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(searchControl);
}
}, },
/** /**
* Create the pop-up infobox for when you click on a region, this can't * Create the pop-up infobox for when you click on a region, this can't

View File

@@ -50,9 +50,18 @@ var overviewerConfig = {
*/ */
'mapType': true, 'mapType': true,
/** /**
* The small box at the bottom that displays the link to the current map view. * The coordsBox control is the box showing the XYZ coordinates
* under the cursor.
*/ */
'link': true 'coordsBox': true,
/**
* The overlays control is the drop-down box for selecting overlays.
*/
'overlays': true,
/**
* The searchBox control is the search box for markers.
*/
'searchBox': true
}, },
/** /**
* The zoom level when the page is loaded without a specific zoom setting * The zoom level when the page is loaded without a specific zoom setting
@@ -66,6 +75,12 @@ var overviewerConfig = {
* This controls how close you can zoom in. * This controls how close you can zoom in.
*/ */
'maxZoom': {maxzoom}, 'maxZoom': {maxzoom},
/**
* This tells us how many total zoom levels Overviewer rendered.
* DO NOT change this, even if you change minZoom and maxZoom, because
* it's used for marker position calculations and map resizing.
*/
'zoomLevels': {zoomlevels},
/** /**
* Center on this point, in world coordinates. Should be an array, ex: * Center on this point, in world coordinates. Should be an array, ex:
* [0,0,0] * [0,0,0]

View File

@@ -114,6 +114,8 @@ class MapGen(object):
"{minzoom}", str(0)) "{minzoom}", str(0))
config = config.replace( config = config.replace(
"{maxzoom}", str(zoomlevel)) "{maxzoom}", str(zoomlevel))
config = config.replace(
"{zoomlevels}", str(zoomlevel))
config = config.replace("{spawn_coords}", config = config.replace("{spawn_coords}",
json.dumps(list(self.world.spawn))) json.dumps(list(self.world.spawn)))

View File

@@ -120,7 +120,7 @@ class QuadtreeGen(object):
indexfile = os.path.join(self.destdir, "overviewerConfig.js") indexfile = os.path.join(self.destdir, "overviewerConfig.js")
if not os.path.exists(indexfile): if not os.path.exists(indexfile):
return -1 return -1
matcher = re.compile(r"maxZoom.*:\s*(\d+)") matcher = re.compile(r"zoomLevels(?:\'|\")\s*:\s*(\d+)")
p = -1 p = -1
for line in open(indexfile, "r"): for line in open(indexfile, "r"):
res = matcher.search(line) res = matcher.search(line)
@@ -426,21 +426,21 @@ class QuadtreeGen(object):
needs_rerender = False needs_rerender = False
get_region_mtime = world.get_region_mtime get_region_mtime = world.get_region_mtime
for col, row, chunkx, chunky, regionfile in chunks: for col, row, chunkx, chunky, regionfile in chunks:
region, regionMtime = get_region_mtime(regionfile)
# don't even check if it's not in the regionlist
if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
continue
# bail early if forcerender is set # bail early if forcerender is set
if self.forcerender: if self.forcerender:
needs_rerender = True needs_rerender = True
break break
# check region file mtime first. # check region file mtime first.
region,regionMtime = get_region_mtime(regionfile)
if regionMtime <= tile_mtime: if regionMtime <= tile_mtime:
continue continue
# don't even check if it's not in the regionlist
if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
continue
# checking chunk mtime # checking chunk mtime
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime: if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime:
needs_rerender = True needs_rerender = True

View File

@@ -173,12 +173,18 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) {
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f); data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f);
return data; return data;
} }
} else if (state->block == 20) { /* glass */
/* an aditional bit for top is added to the 4 bits of check_adjacent_blocks */
if ((z != 127) && (getArrayByte3D(state->blocks, x, y, z+1) == 20)) {
data = 0;
} else {
data = 16;
}
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f) | data;
return data;
} else if (state->block == 85) { /* fences */ } else if (state->block == 85) { /* fences */
return check_adjacent_blocks(state, x, y, z, state->block); return check_adjacent_blocks(state, x, y, z, state->block);
} else if (state->block == 55) { /* redstone */ } else if (state->block == 55) { /* redstone */
/* three addiotional bit are added, one for on/off state, and /* three addiotional bit are added, one for on/off state, and
* another two for going-up redstone wire in the same block * another two for going-up redstone wire in the same block
@@ -352,6 +358,10 @@ chunk_render(PyObject *self, PyObject *args) {
up_right_blocks_py = PyObject_GetAttrString(state.self, "up_right_blocks"); up_right_blocks_py = PyObject_GetAttrString(state.self, "up_right_blocks");
state.up_right_blocks = up_right_blocks_py; state.up_right_blocks = up_right_blocks_py;
/* set up the random number generator again for each chunk
so tallgrass is in the same place, no matter what mode is used */
srand(1);
for (state.x = 15; state.x > -1; state.x--) { for (state.x = 15; state.x > -1; state.x--) {
for (state.y = 0; state.y < 16; state.y++) { for (state.y = 0; state.y < 16; state.y++) {
PyObject *blockid = NULL; PyObject *blockid = NULL;
@@ -364,7 +374,7 @@ chunk_render(PyObject *self, PyObject *args) {
for (state.z = 0; state.z < 128; state.z++) { for (state.z = 0; state.z < 128; state.z++) {
state.imgy -= 12; state.imgy -= 12;
/* get blockid */ /* get blockid */
state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z); state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z);
if (state.block == 0) { if (state.block == 0) {
continue; continue;
@@ -400,7 +410,10 @@ chunk_render(PyObject *self, PyObject *args) {
PyObject *tmp; PyObject *tmp;
unsigned char ancilData = getArrayByte3D(state.blockdata_expanded, state.x, state.y, state.z); unsigned char ancilData = getArrayByte3D(state.blockdata_expanded, state.x, state.y, state.z);
if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2) || (state.block == 90)) { if ((state.block == 2) || (state.block == 9) ||
(state.block == 20) || (state.block == 54) ||
(state.block == 55) || (state.block == 85) ||
(state.block == 90)) {
ancilData = generate_pseudo_data(&state, ancilData); ancilData = generate_pseudo_data(&state, ancilData);
} }
@@ -419,14 +432,29 @@ chunk_render(PyObject *self, PyObject *args) {
if (t != NULL && t != Py_None) if (t != NULL && t != Py_None)
{ {
PyObject *src, *mask, *mask_light; PyObject *src, *mask, *mask_light;
int randx = 0, randy = 0;
src = PyTuple_GetItem(t, 0); src = PyTuple_GetItem(t, 0);
mask = PyTuple_GetItem(t, 1); mask = PyTuple_GetItem(t, 1);
mask_light = PyTuple_GetItem(t, 2); mask_light = PyTuple_GetItem(t, 2);
if (mask == Py_None) if (mask == Py_None)
mask = src; mask = src;
if (state.block == 31) {
/* add a random offset to the postion of the tall grass to make it more wild */
randx = rand() % 6 + 1 - 3;
randy = rand() % 6 + 1 - 3;
state.imgx += randx;
state.imgy += randy;
}
render_mode_draw(rendermode, src, mask, mask_light); render_mode_draw(rendermode, src, mask, mask_light);
if (state.block == 31) {
/* undo the random offsets */
state.imgx -= randx;
state.imgy -= randy;
}
} }
} }

View File

@@ -154,7 +154,6 @@ rendermode_normal_occluded(void *data, RenderState *state, int x, int y, int z)
static void static void
rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) { rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
RenderModeNormal *self = (RenderModeNormal *)data; RenderModeNormal *self = (RenderModeNormal *)data;
int randx = 0,randy = 0;
unsigned char data_byte; unsigned char data_byte;
/* first, check to see if we should use biome-compatible src, mask */ /* first, check to see if we should use biome-compatible src, mask */
@@ -162,11 +161,6 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
if (state->block == 18) { if (state->block == 18) {
src = mask = self->leaf_texture; src = mask = self->leaf_texture;
} else if (state->block == 31) { } else if (state->block == 31) {
/* add a random offset to the postion of the tall grass to make it more wild */
randx = rand() % 6 + 1 - 3;
randy = rand() % 6 + 1 - 3;
state->imgx = state->imgx + randx;
state->imgy = state->imgy + randy;
data_byte = getArrayByte3D(state->blockdata_expanded, state->x, state->y, state->z); data_byte = getArrayByte3D(state->blockdata_expanded, state->x, state->y, state->z);
if (data_byte == 1) { if (data_byte == 1) {
src = mask = self->tall_grass_texture; src = mask = self->tall_grass_texture;

View File

@@ -28,7 +28,7 @@ import util
import composite import composite
_find_file_local_path = None _find_file_local_path = None
def _find_file(filename, mode="rb"): def _find_file(filename, mode="rb", verbose=False):
"""Searches for the given file and returns an open handle to it. """Searches for the given file and returns an open handle to it.
This searches the following locations in this order: This searches the following locations in this order:
@@ -47,11 +47,13 @@ def _find_file(filename, mode="rb"):
if _find_file_local_path: if _find_file_local_path:
path = os.path.join(_find_file_local_path, filename) path = os.path.join(_find_file_local_path, filename)
if os.path.exists(path): if os.path.exists(path):
if verbose: print "Found %s in '%s'" % (filename, path)
return open(path, mode) return open(path, mode)
programdir = util.get_program_path() programdir = util.get_program_path()
path = os.path.join(programdir, filename) path = os.path.join(programdir, filename)
if os.path.exists(path): if os.path.exists(path):
if verbose: print "Found %s in '%s'" % (filename, path)
return open(path, mode) return open(path, mode)
path = os.path.join(programdir, "overviewer_core", "data", "textures", filename) path = os.path.join(programdir, "overviewer_core", "data", "textures", filename)
@@ -61,11 +63,13 @@ def _find_file(filename, mode="rb"):
# windows special case, when the package dir doesn't exist # windows special case, when the package dir doesn't exist
path = os.path.join(programdir, "textures", filename) path = os.path.join(programdir, "textures", filename)
if os.path.exists(path): if os.path.exists(path):
if verbose: print "Found %s in '%s'" % (filename, path)
return open(path, mode) return open(path, mode)
if sys.platform == "darwin": if sys.platform == "darwin":
path = os.path.join("/Applications/Minecraft", filename) path = os.path.join("/Applications/Minecraft", filename)
if os.path.exists(path): if os.path.exists(path):
if verbose: print "Found %s in '%s'" % (filename, path)
return open(path, mode) return open(path, mode)
# Find minecraft.jar. # Find minecraft.jar.
@@ -85,6 +89,7 @@ def _find_file(filename, mode="rb"):
if os.path.exists(jarpath): if os.path.exists(jarpath):
try: try:
jar = zipfile.ZipFile(jarpath) jar = zipfile.ZipFile(jarpath)
if verbose: print "Found %s in '%s'" % (filename, jarpath)
return jar.open(filename) return jar.open(filename)
except (KeyError, IOError): except (KeyError, IOError):
pass pass
@@ -321,34 +326,34 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
A non transparent block uses top, side 3 and side 4. A non transparent block uses top, side 3 and side 4.
If top is a tuple then first member is the top image and the second If top is a tuple then first item is the top image and the second
member is an increment (integer) from 0 to 12. This increment will item is an increment (integer) from 0 to 16 (pixels in the
used to crop the side images to look like a block and to paste all original minecraft texture). This increment will be used to crop the
the images increment pixels lower. Using increment = 6 will create side images and to paste the top image increment pixels lower, so if
a half-block. you use an increment of 8, it willll draw a half-block.
NOTE: this method uses the top of the texture image (as done in NOTE: this method uses the bottom of the texture image (as done in
minecraft with beds) minecraft with beds and cackes)
""" """
increment = 0 increment = 0
if isinstance(top, tuple): if isinstance(top, tuple):
increment = top[1] increment = int(round((top[1] / 16.)*12.)) # range increment in the block height in pixels (half texture size)
crop_height = int(increment * 16./12.) crop_height = increment
top = top[0] top = top[0]
if side1 != None: if side1 != None:
side1 = side1.copy() side1 = side1.copy()
ImageDraw.Draw(side1).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) ImageDraw.Draw(side1).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
if side2 != None: if side2 != None:
side2 = side2.copy() side2 = side2.copy()
ImageDraw.Draw(side2).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) ImageDraw.Draw(side2).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
if side3 != None: if side3 != None:
side3 = side3.copy() side3 = side3.copy()
ImageDraw.Draw(side3).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) ImageDraw.Draw(side3).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
if side4 != None: if side4 != None:
side4 = side4.copy() side4 = side4.copy()
ImageDraw.Draw(side4).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) ImageDraw.Draw(side4).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
@@ -362,7 +367,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
side1 = ImageEnhance.Brightness(side1).enhance(0.9) side1 = ImageEnhance.Brightness(side1).enhance(0.9)
side1.putalpha(sidealpha) side1.putalpha(sidealpha)
composite.alpha_over(img, side1, (0,0 + increment), side1) composite.alpha_over(img, side1, (0,0), side1)
if side2 != None : if side2 != None :
@@ -373,11 +378,11 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
side2 = ImageEnhance.Brightness(side2).enhance(0.8) side2 = ImageEnhance.Brightness(side2).enhance(0.8)
side2.putalpha(sidealpha2) side2.putalpha(sidealpha2)
composite.alpha_over(img, side2, (12,0 + increment), side2) composite.alpha_over(img, side2, (12,0), side2)
if bottom != None : if bottom != None :
bottom = transform_image(bottom, blockID) bottom = transform_image(bottom, blockID)
composite.alpha_over(img, bottom, (0,12), top) composite.alpha_over(img, bottom, (0,12), bottom)
# front sides # front sides
if side3 != None : if side3 != None :
@@ -388,7 +393,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
side3 = ImageEnhance.Brightness(side3).enhance(0.9) side3 = ImageEnhance.Brightness(side3).enhance(0.9)
side3.putalpha(sidealpha) side3.putalpha(sidealpha)
composite.alpha_over(img, side3, (0,6 + increment), side3) composite.alpha_over(img, side3, (0,6), side3)
if side4 != None : if side4 != None :
side4 = transform_image_side(side4, blockID) side4 = transform_image_side(side4, blockID)
@@ -399,7 +404,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
side4 = ImageEnhance.Brightness(side4).enhance(0.8) side4 = ImageEnhance.Brightness(side4).enhance(0.8)
side4.putalpha(sidealpha) side4.putalpha(sidealpha)
composite.alpha_over(img, side4, (12,6 + increment), side4) composite.alpha_over(img, side4, (12,6), side4)
if top != None : if top != None :
top = transform_image(top, blockID) top = transform_image(top, blockID)
@@ -420,7 +425,7 @@ def _build_blockimages():
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
topids = [ -1, 1, 0, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33, topids = [ -1, 1, 0, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33,
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, 11, -1, 34, -1, 52, 48, -1,160,144, -1,176, 74, -1, -1, -1, -1, 11, -1,
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 9, 4, 55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 9, 4,
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
@@ -437,7 +442,7 @@ def _build_blockimages():
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
sideids = [ -1, 1, 3, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33, sideids = [ -1, 1, 3, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33,
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
34, -1, 52, 48, 49,160,144, -1,192, 74, -1, -1,- 1, -1, 11, -1, 34, -1, 52, 48, -1,160,144, -1,192, 74, -1, -1,- 1, -1, 11, -1,
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 # 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35, 55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35,
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 # 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
@@ -548,33 +553,35 @@ def generate_special_texture(blockID, data):
return generate_texture_tuple(img, blockID) return generate_texture_tuple(img, blockID)
if blockID == 9: # spring water, flowing water and waterfall water if blockID == 9 or blockID == 20: # spring water, flowing water and waterfall water, AND glass
# water and glass share the way to be rendered
watertexture = _load_image("water.png") if blockID == 9:
texture = _load_image("water.png")
else:
texture = terrain_images[49]
if (data & 0b10000) == 16: if (data & 0b10000) == 16:
top = watertexture top = texture
else: top = None else: top = None
if (data & 0b0001) == 1: if (data & 0b0001) == 1:
side1 = watertexture # top left side1 = texture # top left
else: side1 = None else: side1 = None
if (data & 0b1000) == 8: if (data & 0b1000) == 8:
side2 = watertexture # top right side2 = texture # top right
else: side2 = None else: side2 = None
if (data & 0b0010) == 2: if (data & 0b0010) == 2:
side3 = watertexture # bottom left side3 = texture # bottom left
else: side3 = None else: side3 = None
if (data & 0b0100) == 4: if (data & 0b0100) == 4:
side4 = watertexture # bottom right side4 = texture # bottom right
else: side4 = None else: side4 = None
img = _build_full_block(top,None,None,side3,side4) img = _build_full_block(top,None,None,side3,side4)
return generate_texture_tuple(img, blockID) return generate_texture_tuple(img, blockID)
@@ -600,7 +607,7 @@ def generate_special_texture(blockID, data):
if blockID == 26: # bed if blockID == 26: # bed
increment = 5 increment = 8
left_face = None left_face = None
right_face = None right_face = None
if data & 0x8 == 0x8: # head of the bed if data & 0x8 == 0x8: # head of the bed
@@ -644,6 +651,7 @@ def generate_special_texture(blockID, data):
return generate_texture_tuple(img, blockID) return generate_texture_tuple(img, blockID)
if blockID == 31: # tall grass if blockID == 31: # tall grass
if data == 0: # dead shrub if data == 0: # dead shrub
texture = terrain_images[55] texture = terrain_images[55]
@@ -656,8 +664,134 @@ def generate_special_texture(blockID, data):
img = _build_block(texture, texture, blockID) img = _build_block(texture, texture, blockID)
return generate_texture_tuple(img,31) return generate_texture_tuple(img,31)
if blockID in (29,33): # sticky and normal body piston.
if blockID == 29: # sticky
piston_t = terrain_images[106].copy()
else: # normal
piston_t = terrain_images[107].copy()
# other textures
side_t = terrain_images[108].copy()
back_t = terrain_images[109].copy()
interior_t = terrain_images[110].copy()
if data & 0x08 == 0x08: # pushed out, non full blocks, tricky stuff
# remove piston texture from piston body
ImageDraw.Draw(side_t).rectangle((0, 0,16,3),outline=(0,0,0,0),fill=(0,0,0,0))
if data & 0x07 == 0x0: # down
side_t = side_t.rotate(180)
img = _build_full_block(back_t ,None ,None ,side_t, side_t)
elif data & 0x07 == 0x1: # up
img = _build_full_block((interior_t, 4) ,None ,None ,side_t, side_t)
elif data & 0x07 == 0x2: # east
img = _build_full_block(side_t , None, None ,side_t.rotate(90), back_t)
elif data & 0x07 == 0x3: # west
img = _build_full_block(side_t.rotate(180) ,None ,None ,side_t.rotate(270), None)
temp = transform_image_side(interior_t, blockID)
temp = temp.transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, temp, (9,5), temp)
elif data & 0x07 == 0x4: # north
img = _build_full_block(side_t.rotate(90) ,None ,None , None, side_t.rotate(270))
temp = transform_image_side(interior_t, blockID)
composite.alpha_over(img, temp, (3,5), temp)
elif data & 0x07 == 0x5: # south
img = _build_full_block(side_t.rotate(270) ,None , None ,back_t, side_t.rotate(90))
else: # pushed in, normal full blocks, easy stuff
if data & 0x07 == 0x0: # down
side_t = side_t.rotate(180)
img = _build_full_block(back_t ,None ,None ,side_t, side_t)
elif data & 0x07 == 0x1: # up
img = _build_full_block(piston_t ,None ,None ,side_t, side_t)
elif data & 0x07 == 0x2: # east
img = _build_full_block(side_t ,None ,None ,side_t.rotate(90), back_t)
elif data & 0x07 == 0x3: # west
img = _build_full_block(side_t.rotate(180) ,None ,None ,side_t.rotate(270), piston_t)
elif data & 0x07 == 0x4: # north
img = _build_full_block(side_t.rotate(90) ,None ,None ,piston_t, side_t.rotate(270))
elif data & 0x07 == 0x5: # south
img = _build_full_block(side_t.rotate(270) ,None ,None ,back_t, side_t.rotate(90))
return generate_texture_tuple(img, blockID)
if blockID == 34: # piston extension (sticky and normal)
if (data & 0x8) == 0x8: # sticky
piston_t = terrain_images[106].copy()
else: # normal
piston_t = terrain_images[107].copy()
# other textures
side_t = terrain_images[108].copy()
back_t = terrain_images[107].copy()
# crop piston body
ImageDraw.Draw(side_t).rectangle((0, 4,16,16),outline=(0,0,0,0),fill=(0,0,0,0))
# generate the horizontal piston extension stick
h_stick = Image.new("RGBA", (24,24), (38,92,255,0))
temp = transform_image_side(side_t, blockID)
composite.alpha_over(h_stick, temp, (1,7), temp)
temp = transform_image(side_t.rotate(90))
composite.alpha_over(h_stick, temp, (1,1), temp)
# Darken it
sidealpha = h_stick.split()[3]
h_stick = ImageEnhance.Brightness(h_stick).enhance(0.85)
h_stick.putalpha(sidealpha)
# generate the vertical piston extension stick
v_stick = Image.new("RGBA", (24,24), (38,92,255,0))
temp = transform_image_side(side_t.rotate(90), blockID)
composite.alpha_over(v_stick, temp, (12,6), temp)
temp = temp.transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(v_stick, temp, (1,6), temp)
# Darken it
sidealpha = v_stick.split()[3]
v_stick = ImageEnhance.Brightness(v_stick).enhance(0.85)
v_stick.putalpha(sidealpha)
# Piston orientation is stored in the 3 first bits
if data & 0x07 == 0x0: # down
side_t = side_t.rotate(180)
img = _build_full_block((back_t, 12) ,None ,None ,side_t, side_t)
composite.alpha_over(img, v_stick, (0,-3), v_stick)
elif data & 0x07 == 0x1: # up
img = Image.new("RGBA", (24,24), (38,92,255,0))
img2 = _build_full_block(piston_t ,None ,None ,side_t, side_t)
composite.alpha_over(img, v_stick, (0,4), v_stick)
composite.alpha_over(img, img2, (0,0), img2)
elif data & 0x07 == 0x2: # east
img = _build_full_block(side_t ,None ,None ,side_t.rotate(90), None)
temp = transform_image_side(back_t, blockID).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, temp, (2,2), temp)
composite.alpha_over(img, h_stick, (6,3), h_stick)
elif data & 0x07 == 0x3: # west
img = Image.new("RGBA", (24,24), (38,92,255,0))
img2 = _build_full_block(side_t.rotate(180) ,None ,None ,side_t.rotate(270), piston_t)
composite.alpha_over(img, h_stick, (0,0), h_stick)
composite.alpha_over(img, img2, (0,0), img2)
elif data & 0x07 == 0x4: # north
img = _build_full_block(side_t.rotate(90) ,None ,None , piston_t, side_t.rotate(270))
composite.alpha_over(img, h_stick.transpose(Image.FLIP_LEFT_RIGHT), (0,0), h_stick.transpose(Image.FLIP_LEFT_RIGHT))
elif data & 0x07 == 0x5: # south
img = Image.new("RGBA", (24,24), (38,92,255,0))
img2 = _build_full_block(side_t.rotate(270) ,None ,None ,None, side_t.rotate(90))
temp = transform_image_side(back_t, blockID)
composite.alpha_over(img2, temp, (10,2), temp)
composite.alpha_over(img, img2, (0,0), img2)
composite.alpha_over(img, h_stick.transpose(Image.FLIP_LEFT_RIGHT), (-3,2), h_stick.transpose(Image.FLIP_LEFT_RIGHT))
return generate_texture_tuple(img, blockID)
if blockID == 35: # wool if blockID == 35: # wool
if data == 0: # white if data == 0: # white
top = side = terrain_images[64] top = side = terrain_images[64]
@@ -1076,7 +1210,7 @@ def generate_special_texture(blockID, data):
# mask out the high bits to figure out the orientation # mask out the high bits to figure out the orientation
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
if (data & 0x03) == 0: if (data & 0x03) == 0: # northeast corner
if not swung: if not swung:
tex = transform_image_side(raw_door) tex = transform_image_side(raw_door)
composite.alpha_over(img, tex, (0,6), tex) composite.alpha_over(img, tex, (0,6), tex)
@@ -1086,7 +1220,7 @@ def generate_special_texture(blockID, data):
tex = tex.transpose(Image.FLIP_LEFT_RIGHT) tex = tex.transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
if (data & 0x03) == 1: if (data & 0x03) == 1: # southeast corner
if not swung: if not swung:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
@@ -1094,7 +1228,7 @@ def generate_special_texture(blockID, data):
tex = transform_image_side(raw_door) tex = transform_image_side(raw_door)
composite.alpha_over(img, tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
if (data & 0x03) == 2: if (data & 0x03) == 2: # southwest corner
if not swung: if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
composite.alpha_over(img, tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
@@ -1102,7 +1236,7 @@ def generate_special_texture(blockID, data):
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
if (data & 0x03) == 3: if (data & 0x03) == 3: # northwest corner
if not swung: if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT)
composite.alpha_over(img, tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
@@ -1388,21 +1522,21 @@ def generate_special_texture(blockID, data):
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
composite.alpha_over(img, side, (1,12), side) composite.alpha_over(img, side, (1,6), side)
composite.alpha_over(img, otherside, (11,13), otherside) # workaround, fixes a hole composite.alpha_over(img, otherside, (11,7), otherside) # workaround, fixes a hole
composite.alpha_over(img, otherside, (12,12), otherside) composite.alpha_over(img, otherside, (12,6), otherside)
composite.alpha_over(img, top, (0,6), top) composite.alpha_over(img, top, (0,6), top)
return generate_texture_tuple(img, blockID) return generate_texture_tuple(img, blockID)
if blockID in (93, 94): # redstone repeaters, ON and OFF if blockID in (93, 94): # redstone repeaters (diodes), ON and OFF
# NOTE: this function uses the redstone torches generated above, # NOTE: this function uses the redstone torches generated above,
# this must run after the function of the torches. # this must run after the function of the torches.
top = terrain_images[131] if blockID == 93 else terrain_images[147] top = terrain_images[131] if blockID == 93 else terrain_images[147]
side = terrain_images[5] side = terrain_images[5]
increment = 9 increment = 13
if (data & 0x3) == 0: # pointing east if (data & 0x3) == 0: # pointing east
pass pass
@@ -1527,7 +1661,7 @@ def generate_special_texture(blockID, data):
img = _build_full_block(None, None, None, texture, None) img = _build_full_block(None, None, None, texture, None)
elif data & 0x4 == 0: # closed trapdoor elif data & 0x4 == 0: # closed trapdoor
img = _build_full_block((texture, 9), None, None, texture, texture) img = _build_full_block((texture, 12), None, None, texture, texture)
return generate_texture_tuple(img, blockID) return generate_texture_tuple(img, blockID)
@@ -1604,9 +1738,10 @@ def getBiomeData(worlddir, chunkX, chunkY):
# (when adding new blocks here and in generate_special_textures, # (when adding new blocks here and in generate_special_textures,
# please, if possible, keep the ascending order of blockid value) # please, if possible, keep the ascending order of blockid value)
special_blocks = set([ 2, 6, 9, 17, 18, 26, 23, 27, 28, 31, 35, 43, 44, special_blocks = set([ 2, 6, 9, 17, 18, 20, 26, 23, 27, 28, 29, 31, 33,
50, 51, 53, 54, 55, 58, 59, 61, 62, 63, 64, 65, 66, 34, 35, 43, 44, 50, 51, 53, 54, 55, 58, 59, 61, 62,
67, 68, 71, 75, 76, 85, 86, 90, 91, 92, 93, 94, 96]) 63, 64, 65, 66, 67, 68, 71, 75, 76, 85, 86, 90, 91,
92, 93, 94, 96])
# this is a map of special blockIDs to a list of all # this is a map of special blockIDs to a list of all
# possible values for ancillary data that it might have. # possible values for ancillary data that it might have.
@@ -1616,10 +1751,14 @@ special_map = {}
special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings) special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings)
special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data
special_map[17] = range(3) # wood: normal, birch and pine special_map[17] = range(3) # wood: normal, birch and pine
special_map[20] = range(32) # glass, used to only render the exterior surface, uses pseudo data
special_map[26] = range(12) # bed, orientation special_map[26] = range(12) # bed, orientation
special_map[23] = range(6) # dispensers, orientation special_map[23] = range(6) # dispensers, orientation
special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered
special_map[28] = range(6) # detector rail, orientation/slope special_map[28] = range(6) # detector rail, orientation/slope
special_map[29] = (0,1,2,3,4,5,8,9,10,11,12,13) # sticky piston body, orientation, pushed in/out
special_map[33] = (0,1,2,3,4,5,8,9,10,11,12,13) # normal piston body, orientation, pushed in/out
special_map[34] = (0,1,2,3,4,5,8,9,10,11,12,13) # normal and sticky piston extension, orientation, sticky/normal
special_map[35] = range(16) # wool, colored and white special_map[35] = range(16) # wool, colored and white
special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-slab special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-slab
special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab
@@ -1670,9 +1809,10 @@ biome_tall_fern_texture = None
biome_leaf_texture = None biome_leaf_texture = None
specialblockmap = None specialblockmap = None
def generate(path=None): def generate(path=None,texture_size=24):
global _find_file_local_path global _find_file_local_path, texture_dimensions
_find_file_local_path = path _find_file_local_path = path
texture_dimensions = (texture_size, texture_size)
# This maps terainids to 16x16 images # This maps terainids to 16x16 images
global terrain_images global terrain_images
@@ -1696,3 +1836,30 @@ def generate(path=None):
for blockID in special_blocks: for blockID in special_blocks:
for data in special_map[blockID]: for data in special_map[blockID]:
specialblockmap[(blockID, data)] = generate_special_texture(blockID, data) specialblockmap[(blockID, data)] = generate_special_texture(blockID, data)
if texture_size != 24:
# rescale biome textures.
biome_grass_texture = biome_grass_texture.resize(texture_dimensions, Image.ANTIALIAS)
biome_leaf_texture = biome_leaf_texture.resize(texture_dimensions, Image.ANTIALIAS)
biome_tall_grass_texture = biome_tall_grass_texture.resize(texture_dimensions, Image.ANTIALIAS)
biome_tall_fern_texture = biome_tall_fern_texture.resize(texture_dimensions, Image.ANTIALIAS)
# rescale the normal block images
for i in range(len(blockmap)):
if blockmap[i] != None:
block = blockmap[i]
alpha = block[1]
block = block[0]
block.putalpha(alpha)
scaled_block = block.resize(texture_dimensions, Image.ANTIALIAS)
blockmap[i] = generate_texture_tuple(scaled_block, i)
# rescale the special block images
for blockid, data in iter(specialblockmap):
block = specialblockmap[(blockid,data)]
if block != None:
alpha = block[1]
block = block[0]
block.putalpha(alpha)
scaled_block = block.resize(texture_dimensions, Image.ANTIALIAS)
specialblockmap[(blockid,data)] = generate_texture_tuple(scaled_block, blockid)

View File

@@ -209,25 +209,27 @@ class World(object):
chunkX = spawnX/16 chunkX = spawnX/16
chunkY = spawnZ/16 chunkY = spawnZ/16
## The filename of this chunk try:
chunkFile = self.get_region_path(chunkX, chunkY) ## The filename of this chunk
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)[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))
## The block for spawn *within* the chunk ## The block for spawn *within* the chunk
inChunkX = spawnX - (chunkX*16) inChunkX = spawnX - (chunkX*16)
inChunkZ = spawnZ - (chunkY*16) inChunkZ = spawnZ - (chunkY*16)
## find the first air block ## find the first air block
while (blockArray[inChunkX, inChunkZ, spawnY] != 0): while (blockArray[inChunkX, inChunkZ, spawnY] != 0):
spawnY += 1 spawnY += 1
if spawnY == 128: if spawnY == 128:
break break
except ChunkCorrupt:
#ignore corrupt spawn, and continue
pass
self.POI.append( dict(x=spawnX, y=spawnY, z=spawnZ, self.POI.append( dict(x=spawnX, y=spawnY, z=spawnZ,
msg="Spawn", type="spawn", chunk=(chunkX, chunkY))) msg="Spawn", type="spawn", chunk=(chunkX, chunkY)))
self.spawn = (spawnX, spawnY, spawnZ) self.spawn = (spawnX, spawnY, spawnZ)

View File

@@ -6,6 +6,7 @@ from distutils.command.build import build
from distutils.command.clean import clean from distutils.command.clean import clean
from distutils.command.build_ext import build_ext from distutils.command.build_ext import build_ext
from distutils.command.sdist import sdist from distutils.command.sdist import sdist
from distutils.cmd import Command
from distutils.dir_util import remove_tree from distutils.dir_util import remove_tree
from distutils.sysconfig import get_python_inc from distutils.sysconfig import get_python_inc
from distutils import log from distutils import log
@@ -74,6 +75,17 @@ def recursive_data_files(src, dest=None):
ret.append((current_dest, current_sources)) ret.append((current_dest, current_sources))
return ret return ret
# helper to create a 'package_data'-type sequence recursively for a given dir
def recursive_package_data(src, package_dir='overviewer_core'):
full_src = os.path.join(package_dir, src)
ret = []
for dirpath, dirnames, filenames in os.walk(full_src, topdown=False):
current_path = os.path.relpath(dirpath, package_dir)
for filename in filenames:
ret.append(os.path.join(current_path, filename))
return ret
# #
# py2exe options # py2exe options
# #
@@ -105,9 +117,8 @@ if py2app is not None:
setup_kwargs['packages'] = ['overviewer_core'] setup_kwargs['packages'] = ['overviewer_core']
setup_kwargs['scripts'] = ['overviewer.py'] setup_kwargs['scripts'] = ['overviewer.py']
setup_kwargs['package_data'] = {'overviewer_core': setup_kwargs['package_data'] = {'overviewer_core': recursive_package_data('data/textures') + recursive_package_data('data/web_assets')}
['data/textures/*',
'data/web_assets/*']}
if py2exe is None: if py2exe is None:
setup_kwargs['data_files'] = [('share/doc/minecraft-overviewer', doc_files)] setup_kwargs['data_files'] = [('share/doc/minecraft-overviewer', doc_files)]
@@ -175,12 +186,15 @@ class CustomClean(clean):
pretty_fname) pretty_fname)
versionpath = os.path.join("overviewer_core", "overviewer_version.py") versionpath = os.path.join("overviewer_core", "overviewer_version.py")
try: if os.path.exists(versionpath):
if not self.dry_run: try:
os.remove(versionpath) if not self.dry_run:
log.info("removing '%s'", versionpath) os.remove(versionpath)
except OSError: log.info("removing '%s'", versionpath)
log.warn("'%s' could not be cleaned -- permission denied", versionpath) except OSError:
log.warn("'%s' could not be cleaned -- permission denied", versionpath)
else:
log.debug("'%s' does not exist -- can't clean it", versionpath)
# now try to purge all *.pyc files # now try to purge all *.pyc files
for root, dirs, files in os.walk(os.path.join(os.path.dirname(__file__), ".")): for root, dirs, files in os.walk(os.path.join(os.path.dirname(__file__), ".")):
@@ -203,7 +217,7 @@ def generate_version_py():
f.write(outstr) f.write(outstr)
f.close() f.close()
except: except:
print "WARNING: failed to build overview_version file" print "WARNING: failed to build overviewer_version file"
class CustomSDist(sdist): class CustomSDist(sdist):
def run(self): def run(self):
@@ -232,11 +246,32 @@ class CustomBuildExt(build_ext):
self.inplace = True self.inplace = True
build_ext.build_extensions(self) build_ext.build_extensions(self)
class CheckTerrain(Command):
user_options=[]
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
from overviewer_core.textures import _find_file
import hashlib
import zipfile
print "checking..."
try:
f = _find_file("terrain.png", verbose=True)
except IOError:
log.error("Could not find the file terrain.png")
return
h = hashlib.sha1()
h.update(f.read())
log.info("Hash of terrain.png file is: %s", h.hexdigest())
setup_kwargs['cmdclass']['clean'] = CustomClean setup_kwargs['cmdclass']['clean'] = CustomClean
setup_kwargs['cmdclass']['sdist'] = CustomSDist setup_kwargs['cmdclass']['sdist'] = CustomSDist
setup_kwargs['cmdclass']['build'] = CustomBuild setup_kwargs['cmdclass']['build'] = CustomBuild
setup_kwargs['cmdclass']['build_ext'] = CustomBuildExt setup_kwargs['cmdclass']['build_ext'] = CustomBuildExt
setup_kwargs['cmdclass']['check_terrain'] = CheckTerrain
### ###
setup(**setup_kwargs) setup(**setup_kwargs)