From 25fcd5e8bbb3cc64adda1e6970e53ae3a9279e60 Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Tue, 27 Mar 2012 01:44:00 +0200 Subject: [PATCH 01/85] generate player POI out of players dat files The new ids are called "Player" and "PlayerSpawn". EntityId is the name of the player. Everything from the player dat is available in the poi filters. The Player position is the position on last logout. --- genPOI.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/genPOI.py b/genPOI.py index 1caad76..28664f2 100755 --- a/genPOI.py +++ b/genPOI.py @@ -39,6 +39,34 @@ def handleSigns(rset, outputdir, render, rname): rset._pois['TileEntities'] += data['TileEntities'] rset._pois['Entities'] += data['Entities'] +def handlePlayers(rset, render, worldpath): + if not hasattr(rset, "_pois"): + rset._pois = dict(TileEntities=[], Entities=[]) + dimension = {'overworld': 0, + 'nether': -1, + 'end': 1, + 'default': 0}[render['dimension']] + playerdir = os.path.join(worldpath, "players") + rset._pois['Players'] = [] + for playerfile in os.listdir(playerdir): + data = nbt.load(os.path.join(playerdir, playerfile))[1] + playername = playerfile.split(".")[0] + if data['Dimension'] == dimension: + # Position at last logout + data['id'] = "Player" + data['EntityId'] = playername + data['x'] = int(data['Pos'][0]) + data['y'] = int(data['Pos'][1]) + data['z'] = int(data['Pos'][2]) + rset._pois['Players'].append(data) + if "SpawnX" in data and dimension == 0: + # Spawn position (bed or main spawn) + spawn = {"id": "PlayerSpawn", + "EntityId": playername, + "x": data['SpawnX'], + "y": data['SpawnY'], + "z": data['SpawnZ']} + rset._pois['Players'].append(spawn) def main(): helptext = """genPOI @@ -102,6 +130,7 @@ def main(): markers[rname] = [dict(groupName=name, displayName=f.__doc__),] handleSigns(rset, os.path.join(destdir, rname), render, rname) + handlePlayers(rset, render, worldpath) logging.info("Done scanning regions") logging.info("Writing out javascript files") @@ -113,6 +142,9 @@ def main(): for poi in rset._pois['TileEntities']: if flter(poi): markerSetDict[name]['raw'].append(poi) + for poi in rset._pois['Players']: + if flter(poi): + markerSetDict[name]['raw'].append(poi) #print markerSetDict with open(os.path.join(destdir, "markersDB.js"), "w") as output: From 779b38f2a3897fe4f1fa44d5cd88de4a3a39ef65 Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Tue, 27 Mar 2012 02:27:46 +0200 Subject: [PATCH 02/85] use avatars for player markers Avatars are taken from scripts at overviewer.org Do we need caching here? --- overviewer_core/data/js_src/views.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 323c1fc..1e8e5a5 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -302,7 +302,6 @@ overviewer.views.SignControlView = Backbone.View.extend({ }}); } - iconURL = overviewerConfig.CONST.image.signMarker; //dataRoot['markers'] = []; // for (i in dataRoot) { @@ -310,6 +309,14 @@ overviewer.views.SignControlView = Backbone.View.extend({ if (!markersDB[groupName].created) { for (j in markersDB[groupName].raw) { var entity = markersDB[groupName].raw[j]; + if (entity['id'] == 'Player') { + iconURL = "http://overviewer.org/avatar/" + + entity['EntityId']; + } else if (entity['id'] == 'Sign') { + iconURL = overviewerConfig.CONST.image.signMarker; + } else { + iconURL = overviewerConfig.CONST.image.defaultMarker; + } var marker = new google.maps.Marker({ 'position': overviewer.util.fromWorldToLatLng(entity.x, entity.y, entity.z, overviewer.mapView.options.currentTileSet), @@ -318,9 +325,7 @@ overviewer.views.SignControlView = Backbone.View.extend({ 'icon': iconURL, 'visible': false }); - if (entity['id'] == 'Sign') { - overviewer.util.createMarkerInfoWindow(marker); - } + overviewer.util.createMarkerInfoWindow(marker); jQuery.extend(entity, {markerObj: marker}); } markersDB[groupName].created = true; From 122eaee37d92dfefe3ff82024af3e72b3e5c4bcc Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Tue, 27 Mar 2012 02:58:56 +0200 Subject: [PATCH 03/85] add bed marker icon from faithful pack Taken from the Faithful 32 texture pack: http://www.minecraftforum.net/viewtopic.php?f=25&t=77442 --- overviewer_core/assetmanager.py | 1 + overviewer_core/data/js_src/views.js | 2 ++ overviewer_core/data/web_assets/bed.png | Bin 0 -> 631 bytes 3 files changed, 3 insertions(+) create mode 100644 overviewer_core/data/web_assets/bed.png diff --git a/overviewer_core/assetmanager.py b/overviewer_core/assetmanager.py index 6407c1d..983f1e3 100644 --- a/overviewer_core/assetmanager.py +++ b/overviewer_core/assetmanager.py @@ -87,6 +87,7 @@ directory. dump['CONST']['image'] = { 'defaultMarker': 'signpost.png', 'signMarker': 'signpost_icon.png', + 'bedMarker': 'bed.png', 'compass': 'compass_upper-left.png', 'spawnMarker': 'http://google-maps-icons.googlecode.com/files/home.png', 'queryMarker': 'http://google-maps-icons.googlecode.com/files/regroup.png' diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 1e8e5a5..6b46e72 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -312,6 +312,8 @@ overviewer.views.SignControlView = Backbone.View.extend({ if (entity['id'] == 'Player') { iconURL = "http://overviewer.org/avatar/" + entity['EntityId']; + } else if (entity['id'] == 'PlayerSpawn') { + iconURL = overviewerConfig.CONST.image.bedMarker; } else if (entity['id'] == 'Sign') { iconURL = overviewerConfig.CONST.image.signMarker; } else { diff --git a/overviewer_core/data/web_assets/bed.png b/overviewer_core/data/web_assets/bed.png new file mode 100644 index 0000000000000000000000000000000000000000..3645ac0c798e2e81af06c3a255dc5ae8077f5a97 GIT binary patch literal 631 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U|>t~ zc6VX;4}uH!E}zW6z`$AH5n0T@z_$T}8U0TGwPRplU@!6Xb!ET9EX|;<)7Z;o!@$7! z-P6S}B;xSh>Av1fjuOZJ3pcvV&=>HCThrX3AQB~iV6*#QA-Qt<7WMUYoXvX0r3?L> z+SnBrIp+tkaPJj*^zvnZagW*SbL+gD_<48^zj|+eevh%zA){no@4l}q{$JRZJM&W6 z?z8`V9U8K?N_j1vl=FG2!lKqL)(NSRPb~O$uKT?_Vw&scy7PzpoMsy`H6+>fpMITv zMTVUr<^9!+tx@w13r0Awt`-bC6yeYyyivkz`?i#7qp49Ihr$nVuW4I(B*TR1d5zbh z-~%i&tw&~w+X!|irdLNFn!Iv~&aR5;+NocY?D*r>dL=BFdm*hSHoTExr;=>0&Y(; zVfXd*{Y`F8*PNTI?=ohaX_@@)z0)zPm#Z`K*6aI=7x1`Gv7NVDnCq}#`GHmK)k`LK zaOIT9g!6yrXo!)0TxDsr;bW~sit86Et%3#R2QU8XD-)0IZ10@dkjET3lSkri*VU&x gMH;8p$<{Of+`KE@O(At10|Nttr>mdKI;Vst0Pryl3;+NC literal 0 HcmV?d00001 From 6528aa91e7a73c323b05acc2e1ed95a4cc3d103f Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 7 Apr 2012 15:03:06 -0400 Subject: [PATCH 04/85] Added overlay control to HTML --- overviewer_core/data/js_src/util.js | 6 ++ overviewer_core/data/js_src/views.js | 126 ++++++++++++++++++++++++++- overviewer_core/tileset.py | 4 + 3 files changed, 133 insertions(+), 3 deletions(-) diff --git a/overviewer_core/data/js_src/util.js b/overviewer_core/data/js_src/util.js index 0e738da..fff2d77 100644 --- a/overviewer_core/data/js_src/util.js +++ b/overviewer_core/data/js_src/util.js @@ -63,6 +63,10 @@ overviewer.util = { signs.registerEvents(signs); } + var overlayControl = new overviewer.views.OverlayControlView(); + overlayControl.registerEvents(overlayControl); + overlayControl.render(); + var spawnmarker = new overviewer.views.SpawnIconView(); // Update coords on mousemove @@ -116,6 +120,8 @@ overviewer.util = { var worldSelector = new overviewer.views.WorldSelectorView({tagName:'DIV'}); overviewer.collections.worlds.bind("add", worldSelector.render, worldSelector); + + // hook up some events overviewer.mapModel.bind("change:currentWorldView", overviewer.mapView.render, overviewer.mapView); diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 323c1fc..46d5379 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -4,8 +4,11 @@ overviewer.views= {} overviewer.views.WorldView = Backbone.View.extend({ initialize: function(opts) { this.options.mapTypes = []; + this.options.overlayMapTypes = []; this.options.mapTypeIds = []; + this.options.overlayMapTypeIds = []; this.model.get("tileSets").each(function(tset, index, list) { + // ignore overlays: var ops = { getTileUrl: overviewer.gmap.getTileUrlGenerator(tset.get("path"), tset.get("base"), tset.get("imgextension")), 'tileSize': new google.maps.Size( @@ -21,10 +24,21 @@ overviewer.views.WorldView = Backbone.View.extend({ newMapType.alt = "Minecraft " + tset.get("name") + " Map"; newMapType.projection = new overviewer.classes.MapProjection(); - this.options.mapTypes.push(newMapType); - this.options.mapTypeIds.push(overviewerConfig.CONST.mapDivId + this.model.get("name") + tset.get("name")); + if (tset.get("isOverlay")) { + this.options.overlayMapTypes.push(newMapType); + this.options.overlayMapTypeIds.push(overviewerConfig.CONST.mapDivId + this.model.get("name") + tset.get("name")); + } else { + this.options.mapTypes.push(newMapType); + this.options.mapTypeIds.push(overviewerConfig.CONST.mapDivId + this.model.get("name") + tset.get("name")); + } }, this); + + this.model.get("tileSets").each(function(tset, index, list) { + // ignore non-overlays: + if (!tset.get("isOverlay")) { return; }; + + }); }, }); @@ -200,6 +214,112 @@ overviewer.views.GoogleMapView = Backbone.View.extend({ }); +/** + * OverlayControlView + */ +overviewer.views.OverlayControlView = Backbone.View.extend({ + /** OverlayControlVIew::initialize + */ + initialize: function(opts) { + $(this.el).addClass("customControl"); + overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(this.el); + }, + registerEvents: function(me) { + overviewer.mapModel.bind("change:currentWorldView", me.render, me); + + }, + + /** + * OverlayControlView::render + */ + render: function() { + this.el.innerHTML=""; + + // hide all visible overlays: + overviewer.map.overlayMapTypes.clear() + + // if this world has no overlays, don't create this control + var mapTypes = overviewer.mapModel.get('currentWorldView').options.overlayMapTypes; + if (mapTypes.length == 0) { return; } + + + var controlText = document.createElement('DIV'); + controlText.innerHTML = "Overlays"; + + var controlBorder = document.createElement('DIV'); + $(controlBorder).addClass('top'); + this.el.appendChild(controlBorder); + controlBorder.appendChild(controlText); + + var dropdownDiv = document.createElement('DIV'); + $(dropdownDiv).addClass('dropDown'); + this.el.appendChild(dropdownDiv); + dropdownDiv.innerHTML=''; + + $(controlText).click(function() { + $(controlBorder).toggleClass('top-active'); + $(dropdownDiv).toggle(); + }); + + + for (i in mapTypes) { + var mt = mapTypes[i]; + this.addItem({label: mt.name, + name: mt.name, + mt: mt, + + action: function(this_item, checked) { + //console.log(this_item); + if (checked) { + overviewer.map.overlayMapTypes.push(this_item.mt); + } else { + var idx_to_delete = -1; + overviewer.map.overlayMapTypes.forEach(function(e, j) { + if (e == this_item.mt) { + idx_to_delete = j; + } + }); + if (idx_to_delete >= 0) { + overviewer.map.overlayMapTypes.removeAt(idx_to_delete); + } + } + + } + }) + } + + + }, + + addItem: function(item) { + var itemDiv = document.createElement('div'); + var itemInput = document.createElement('input'); + itemInput.type='checkbox'; + + // if this overlay is already visible, set the checkbox + // to checked + overviewer.map.overlayMapTypes.forEach(function(e, j) { + if (e == item.mt) { + itemInput.checked=true; + } + }); + + // give it a name + $(itemInput).attr("_mc_overlayname", item.name); + jQuery(itemInput).click((function(local_item) { + return function(e) { + item.action(local_item, e.target.checked); + }; + })(item)); + + this.$(".dropDown")[0].appendChild(itemDiv); + itemDiv.appendChild(itemInput); + var textNode = document.createElement('text'); + textNode.innerHTML = item.label + '
'; + + itemDiv.appendChild(textNode); + } +}); /** @@ -265,7 +385,7 @@ overviewer.views.SignControlView = Backbone.View.extend({ //var dataRoot = overviewer.collections.markerInfo[curMarkerSet]; var dataRoot = markers[curMarkerSet]; - this.el.innerHTML="" + this.el.innerHTML=""; // if we have no markerSets for this tileset, do nothing: if (!dataRoot) { return; } diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index 4787c64..a2a8f0a 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -32,6 +32,7 @@ from .util import roundrobin from . import nbt from .files import FileReplacer from .optimizeimages import optimize_image +import rendermodes import c_overviewer """ @@ -507,6 +508,8 @@ class TileSet(object): """ def bgcolorformat(color): return "#%02x%02x%02x" % color[0:3] + isOverlay = True in [True for x in self.options.get("rendermode") if isinstance(x, rendermodes.Overlay)] + d = dict(name = self.options.get('title'), zoomLevels = self.treedepth, minZoom = 0, @@ -519,6 +522,7 @@ class TileSet(object): (" - " + self.options.get('dimension') if self.options.get('dimension') != 'default' else ''), last_rendertime = self.max_chunk_mtime, imgextension = self.imgextension, + isOverlay = isOverlay ) if (self.regionset.get_type() == "overworld"): d.update({"spawn": self.options.get("spawn")}) From 94b5f21d10adfae395688f0d91a017ac6e156774 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 7 Apr 2012 16:15:01 -0400 Subject: [PATCH 05/85] Have the world selector control have a correct default --- overviewer_core/data/js_src/util.js | 9 +++++---- overviewer_core/data/js_src/views.js | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/overviewer_core/data/js_src/util.js b/overviewer_core/data/js_src/util.js index fff2d77..350f7f4 100644 --- a/overviewer_core/data/js_src/util.js +++ b/overviewer_core/data/js_src/util.js @@ -117,10 +117,6 @@ overviewer.util = { }); - var worldSelector = new overviewer.views.WorldSelectorView({tagName:'DIV'}); - overviewer.collections.worlds.bind("add", worldSelector.render, worldSelector); - - // hook up some events @@ -131,6 +127,11 @@ overviewer.util = { // Jump to the hash if given overviewer.util.initHash(); + // create this control after initHash so it can correctly select the current world + var worldSelector = new overviewer.views.WorldSelectorView({tagName:'DIV'}); + overviewer.collections.worlds.bind("add", worldSelector.render, worldSelector); + + overviewer.util.initializeMarkers(); /* diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 46d5379..7ecb169 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -54,6 +54,9 @@ overviewer.views.WorldSelectorView = Backbone.View.extend({ var o = document.createElement("option"); o.value = elem.model.get("name"); o.innerHTML = elem.model.get("name"); + if (elem.model == overviewer.mapModel.get("currentWorldView").model) { + o.selected=true; + } $(o).data("viewObj", elem); selectBox.appendChild(o); From f4d43d544ade6cc9dbe2595bfd8e2281b20046d4 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 7 Apr 2012 17:56:30 -0400 Subject: [PATCH 06/85] Styling for the worldselector control --- overviewer_core/data/js_src/views.js | 2 ++ overviewer_core/data/web_assets/overviewer.css | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 7ecb169..cafcb1b 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -47,6 +47,8 @@ overviewer.views.WorldView = Backbone.View.extend({ overviewer.views.WorldSelectorView = Backbone.View.extend({ initialize: function() { if(overviewer.collections.worldViews.length > 1) { + $(this.el).addClass("customControl"); + // a div will have already been created for us, we just // need to register it with the google maps control var selectBox = document.createElement('select'); diff --git a/overviewer_core/data/web_assets/overviewer.css b/overviewer_core/data/web_assets/overviewer.css index 0ae76e5..831a138 100644 --- a/overviewer_core/data/web_assets/overviewer.css +++ b/overviewer_core/data/web_assets/overviewer.css @@ -40,6 +40,17 @@ body { font-family: Arial, sans-serif; } +.customControl > select { + font-size: 12px; + line-height: 160%; + text-align: center; + + border: 1px solid #A9BBDF; + border-radius: 2px 2px; + box-shadow: rgba(0, 0, 0, 0.347656) 2px 2px 3px; + +} + .customControl > div.top { font-size: 12px; line-height: 160%; From 5aefebecbe47e7dcd6a26872c6171a8dd60201e1 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 7 Apr 2012 17:59:46 -0400 Subject: [PATCH 07/85] Fix dereferencing bug, hopefully should address mineral-overlay crash Should fix #633 --- overviewer_core/src/primitives/overlay-mineral.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/src/primitives/overlay-mineral.c b/overviewer_core/src/primitives/overlay-mineral.c index 5d6f22e..b658433 100644 --- a/overviewer_core/src/primitives/overlay-mineral.c +++ b/overviewer_core/src/primitives/overlay-mineral.c @@ -90,6 +90,7 @@ overlay_mineral_start(void *data, RenderState *state, PyObject *support) { /* now do custom initializations */ self = (RenderPrimitiveMineral *)data; + // opt is a borrowed reference. do not deref if (!render_mode_parse_option(support, "minerals", "O", &(opt))) return 1; if (opt && opt != Py_None) { @@ -119,7 +120,6 @@ overlay_mineral_start(void *data, RenderState *state, PyObject *support) { } else { self->minerals = default_minerals; } - Py_XDECREF(opt); /* setup custom color */ self->parent.get_color = get_color; From d6602caa045ba4388a9da57c265e06746e6a03f3 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 7 Apr 2012 20:19:24 -0400 Subject: [PATCH 08/85] Output to stdout instead of stderr Fixes #645 --- overviewer_core/logger.py | 6 +++--- overviewer_core/settingsDefinition.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/overviewer_core/logger.py b/overviewer_core/logger.py index 96850cf..70acf21 100644 --- a/overviewer_core/logger.py +++ b/overviewer_core/logger.py @@ -267,15 +267,15 @@ def configure(loglevel=logging.INFO, verbose=False): logger = logging.getLogger() - outstream = sys.stderr + outstream = sys.stdout if platform.system() == 'Windows': # Our custom output stream processor knows how to deal with select ANSI # color escape sequences - outstream = WindowsOutputStream() + outstream = WindowsOutputStream(outstream) formatter = ANSIColorFormatter(verbose) - elif sys.stderr.isatty(): + elif outstream.isatty(): # terminal logging with ANSI color formatter = ANSIColorFormatter(verbose) diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index 7d1625f..e78c589 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -97,9 +97,9 @@ processes = Setting(required=True, validator=int, default=-1) # ends up adding overhead and isn't worth it. memcached_host = Setting(required=False, validator=str, default=None) -if platform.system() == 'Windows' or not sys.stderr.isatty(): +if platform.system() == 'Windows' or not sys.stdout.isatty(): obs = LoggingObserver() else: - obs = ProgressBarObserver() + obs = ProgressBarObserver(fd=sys.stdout) observer = Setting(required=True, validator=validateObserver, default=obs) From cb448cc58f2d867df68e29e3798e93920e827cd7 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 7 Apr 2012 21:16:58 -0400 Subject: [PATCH 09/85] Added a --simple-output option This option turns off fancy output options like colors or progress bars. Address #649 --- overviewer.py | 5 ++++- overviewer_core/logger.py | 6 ++++-- overviewer_core/settingsDefinition.py | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/overviewer.py b/overviewer.py index 6786c36..210420a 100755 --- a/overviewer.py +++ b/overviewer.py @@ -89,6 +89,8 @@ def main(): help="Print less output. You can specify this option multiple times.") parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0, help="Print more output. You can specify this option multiple times.") + parser.add_option("--simple-output", dest="simple", action="store_true", default=False, + help="Use a simple output format, with no colors or progress bars") # create a group for "plugin exes" (the concept of a plugin exe is only loosly defined at this point) exegroup = OptionGroup(parser, "Other Scripts", @@ -114,7 +116,8 @@ def main(): # re-configure the logger now that we've processed the command line options logger.configure(logging.INFO + 10*options.quiet - 10*options.verbose, - options.verbose > 0) + verbose=options.verbose > 0, + simple=options.simple) ########################################################################## # This section of main() runs in response to any one-time options we have, diff --git a/overviewer_core/logger.py b/overviewer_core/logger.py index 70acf21..4fd36a3 100644 --- a/overviewer_core/logger.py +++ b/overviewer_core/logger.py @@ -254,7 +254,7 @@ class ANSIColorFormatter(HighlightingFormatter): # No coloring if it's not to be highlighted or colored return logging.Formatter.format(self, record) -def configure(loglevel=logging.INFO, verbose=False): +def configure(loglevel=logging.INFO, verbose=False, simple=False): """Configures the root logger to our liking For a non-standard loglevel, pass in the level with which to configure the handler. @@ -268,8 +268,10 @@ def configure(loglevel=logging.INFO, verbose=False): logger = logging.getLogger() outstream = sys.stdout + if simple: + formatter = DumbFormatter(verbose) - if platform.system() == 'Windows': + elif platform.system() == 'Windows': # Our custom output stream processor knows how to deal with select ANSI # color escape sequences outstream = WindowsOutputStream(outstream) diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index e78c589..54fb763 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -97,7 +97,8 @@ processes = Setting(required=True, validator=int, default=-1) # ends up adding overhead and isn't worth it. memcached_host = Setting(required=False, validator=str, default=None) -if platform.system() == 'Windows' or not sys.stdout.isatty(): +# TODO clean up this ugly in sys.argv hack +if platform.system() == 'Windows' or not sys.stdout.isatty() or "--simple" in sys.argv: obs = LoggingObserver() else: obs = ProgressBarObserver(fd=sys.stdout) From 7433f06edbb6dc40f1ff33be360b53dc9941ede3 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 7 Apr 2012 22:12:10 -0400 Subject: [PATCH 10/85] Remove unneeded stuffs --- overviewer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/overviewer.py b/overviewer.py index 210420a..8a774f9 100755 --- a/overviewer.py +++ b/overviewer.py @@ -236,7 +236,6 @@ dir but you forgot to put quotes around the directory, since it contains spaces. return 1 # Parse the config file - mw_parser = configParser.MultiWorldParser() mw_parser.parse(options.config) # Add in the command options here, perhaps overriding values specified in From 3ded0cfa9e3a76f881952a0003e2bc680c3dc4a5 Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Mon, 9 Apr 2012 11:49:03 -0700 Subject: [PATCH 11/85] Add validator and definition for beginnings of overlay python glue so that only the right overlays show up for a specific render --- overviewer_core/settingsDefinition.py | 1 + overviewer_core/settingsValidators.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index 54fb763..dc8a518 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -79,6 +79,7 @@ renders = Setting(required=True, default=util.OrderedDict(), "crop": Setting(required=False, validator=validateCrop, default=None), "changelist": Setting(required=False, validator=validateStr, default=None), "markers": Setting(required=False, validator=validateMarkers, default=[]), + "overlay": Setting(required=False, validator=validateOverlays, default=[]), # Remove this eventually (once people update their configs) "worldname": Setting(required=False, default=None, diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index d8846b1..7b023a8 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -51,6 +51,13 @@ def validateMarkers(filterlist): raise ValidationException("%r must be a function"% x) return filterlist +def validateOverlays(renderlist): + if type(renderlist) != list: + raise ValidationException("Overlay must specify a list of renders") + for x in renderlist: + print x + return renderlist + def validateWorldPath(worldpath): _, worldpath = checkBadEscape(worldpath) abs_path = os.path.abspath(os.path.expanduser(worldpath)) From ebd8b287ed48dca08f46a3145cd8a8ad4d9a0763 Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Mon, 9 Apr 2012 12:20:58 -0700 Subject: [PATCH 12/85] Further glue for overlays. Make the validator actually validate. Also rough outlines for checking if the render you've specified in the overlay actually exists and isn't itself. --- overviewer.py | 15 +++++++++++++++ overviewer_core/settingsValidators.py | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/overviewer.py b/overviewer.py index 8a774f9..2a93845 100755 --- a/overviewer.py +++ b/overviewer.py @@ -304,6 +304,21 @@ dir but you forgot to put quotes around the directory, since it contains spaces. if render.get('forcerender', False): render['renderchecks'] = 2 + # check if overlays are set, if so, make sure that those renders exist + if render.get('overlay', []) != []: + for x in render.get('overlay'): + if x != rname: + try: + renderLink = config['renders'][x] + except KeyError: + logging.error("Render %s's overlay is '%s', but I could not find a corresponding entry in the renders dictionary.", + rname, x) + return 1 + # TODO: Link the overlay rendering to the render modes it is used for so that the JS can properly fill in the dropdown + else: + logging.error("Render %s's overlay contains itself.", rname) + return 1 + destdir = config['outputdir'] if not destdir: logging.error("You must specify the output directory in your config file.") diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index 7b023a8..227f4d3 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -55,7 +55,8 @@ def validateOverlays(renderlist): if type(renderlist) != list: raise ValidationException("Overlay must specify a list of renders") for x in renderlist: - print x + if validateStr(x) == '': + raise ValidationException("%r must be a string"% x) return renderlist def validateWorldPath(worldpath): From 77acd158c6414646a2e4830e5125c311900cd003 Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Mon, 9 Apr 2012 12:26:40 -0700 Subject: [PATCH 13/85] Add docs too! --- docs/config.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/config.rst b/docs/config.rst index 1884573..b2c9df6 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -480,6 +480,18 @@ values. The valid configuration keys are listed below. **Default:** ``[]`` (an empty list) +.. _option_overlay: + +``overlay`` + This specifies which renders that this render will be displayed on top of. + It should be a list of renders. + + .. warning:: + + At this time, this feature is not fully implemented. + + **Default:** ``[]`` (an empty list) + .. _customrendermodes: Custom Rendermodes and Rendermode Primitives From db0a1d3415e802a09bbac1770ed368747bc88fb4 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 9 Apr 2012 17:10:05 -0400 Subject: [PATCH 14/85] updated isOverlay to correctly recognize modes with no Base() primitive --- overviewer_core/tileset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index a2a8f0a..6919884 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -508,7 +508,7 @@ class TileSet(object): """ def bgcolorformat(color): return "#%02x%02x%02x" % color[0:3] - isOverlay = True in [True for x in self.options.get("rendermode") if isinstance(x, rendermodes.Overlay)] + isOverlay = not any(isinstance(x, rendermodes.Base) for x in self.options.get("rendermode")) d = dict(name = self.options.get('title'), zoomLevels = self.treedepth, From b13bbd02048c8c259b8381b533fd8e87975ba78f Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Thu, 12 Apr 2012 08:59:13 -0700 Subject: [PATCH 15/85] Add the JS stuff and a little bit more python glue to make overlays only display for a specified render --- overviewer.py | 2 +- overviewer_core/data/js_src/util.js | 5 +-- overviewer_core/data/js_src/views.js | 47 ++++++++++++++-------------- overviewer_core/tileset.py | 3 ++ 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/overviewer.py b/overviewer.py index 2a93845..0733ddf 100755 --- a/overviewer.py +++ b/overviewer.py @@ -418,7 +418,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces. # only pass to the TileSet the options it really cares about render['name'] = render_name # perhaps a hack. This is stored here for the asset manager - tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist"]) + tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist", "overlay"]) tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir) tilesets.append(tset) diff --git a/overviewer_core/data/js_src/util.js b/overviewer_core/data/js_src/util.js index 350f7f4..81cc5c0 100644 --- a/overviewer_core/data/js_src/util.js +++ b/overviewer_core/data/js_src/util.js @@ -64,8 +64,6 @@ overviewer.util = { } var overlayControl = new overviewer.views.OverlayControlView(); - overlayControl.registerEvents(overlayControl); - overlayControl.render(); var spawnmarker = new overviewer.views.SpawnIconView(); @@ -85,6 +83,9 @@ overviewer.util = { compass.render(); spawnmarker.render(); + // update list of spawn overlays + overlayControl.render(); + // re-center on the last viewport var currentWorldView = overviewer.mapModel.get("currentWorldView"); if (currentWorldView.options.lastViewport) { diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index cafcb1b..21fbaac 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -23,8 +23,9 @@ overviewer.views.WorldView = Backbone.View.extend({ newMapType.shortname = tset.get("name"); newMapType.alt = "Minecraft " + tset.get("name") + " Map"; newMapType.projection = new overviewer.classes.MapProjection(); - + if (tset.get("isOverlay")) { + newMapType.tiles = tset.get("tilesets"); this.options.overlayMapTypes.push(newMapType); this.options.overlayMapTypeIds.push(overviewerConfig.CONST.mapDivId + this.model.get("name") + tset.get("name")); } else { @@ -231,7 +232,6 @@ overviewer.views.OverlayControlView = Backbone.View.extend({ }, registerEvents: function(me) { overviewer.mapModel.bind("change:currentWorldView", me.render, me); - }, /** @@ -246,8 +246,7 @@ overviewer.views.OverlayControlView = Backbone.View.extend({ // if this world has no overlays, don't create this control var mapTypes = overviewer.mapModel.get('currentWorldView').options.overlayMapTypes; if (mapTypes.length == 0) { return; } - - + var controlText = document.createElement('DIV'); controlText.innerHTML = "Overlays"; @@ -265,32 +264,34 @@ overviewer.views.OverlayControlView = Backbone.View.extend({ $(controlBorder).toggleClass('top-active'); $(dropdownDiv).toggle(); }); - + var currentTileSetPath = overviewer.mapView.options.currentTileSet.get('path'); + for (i in mapTypes) { var mt = mapTypes[i]; - this.addItem({label: mt.name, - name: mt.name, - mt: mt, + if (mt.tiles.indexOf(currentTileSetPath)!=-1) { + this.addItem({label: mt.name, + name: mt.name, + mt: mt, - action: function(this_item, checked) { - //console.log(this_item); - if (checked) { - overviewer.map.overlayMapTypes.push(this_item.mt); - } else { - var idx_to_delete = -1; - overviewer.map.overlayMapTypes.forEach(function(e, j) { - if (e == this_item.mt) { - idx_to_delete = j; + action: function(this_item, checked) { + if (checked) { + overviewer.map.overlayMapTypes.push(this_item.mt); + } else { + var idx_to_delete = -1; + overviewer.map.overlayMapTypes.forEach(function(e, j) { + if (e == this_item.mt) { + idx_to_delete = j; + } + }); + if (idx_to_delete >= 0) { + overviewer.map.overlayMapTypes.removeAt(idx_to_delete); } - }); - if (idx_to_delete >= 0) { - overviewer.map.overlayMapTypes.removeAt(idx_to_delete); } - } - } - }) + } + }) + } } diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index 6919884..a08443d 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -524,6 +524,9 @@ class TileSet(object): imgextension = self.imgextension, isOverlay = isOverlay ) + if isOverlay: + d.update({"tilesets": self.options.get("overlay")}) + if (self.regionset.get_type() == "overworld"): d.update({"spawn": self.options.get("spawn")}) try: From 805618dd2fd1763ac676c12fd19e8d598bf0cfdd Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Thu, 12 Apr 2012 09:03:14 -0700 Subject: [PATCH 16/85] remove todo since I did that part --- overviewer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/overviewer.py b/overviewer.py index 0733ddf..728ff82 100755 --- a/overviewer.py +++ b/overviewer.py @@ -314,7 +314,6 @@ dir but you forgot to put quotes around the directory, since it contains spaces. logging.error("Render %s's overlay is '%s', but I could not find a corresponding entry in the renders dictionary.", rname, x) return 1 - # TODO: Link the overlay rendering to the render modes it is used for so that the JS can properly fill in the dropdown else: logging.error("Render %s's overlay contains itself.", rname) return 1 From f5797dd8a0f60d1369d332a620a84584df78db10 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 12 Apr 2012 15:16:19 -0400 Subject: [PATCH 17/85] added a Hide() render primitive --- docs/config.rst | 9 +++ overviewer_core/rendermodes.py | 6 ++ overviewer_core/src/primitives/hide.c | 111 ++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 overviewer_core/src/primitives/hide.c diff --git a/docs/config.rst b/docs/config.rst index 1884573..e7e4c99 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -560,6 +560,15 @@ Cave only_lit Only render lit caves. Default: False +Hide + Hide blocks based on blockid. Blocks hidden in this way will be + treated exactly the same as air. + + **Options** + + minerals + A list of block ids, or (blockid, data) tuples to hide. + DepthTinting Tint blocks a color according to their depth (height) from bedrock. Useful mainly for cave renders. diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py index e1adc9c..8ea0b52 100644 --- a/overviewer_core/rendermodes.py +++ b/overviewer_core/rendermodes.py @@ -188,6 +188,12 @@ class MineralOverlay(Overlay): 'minerals' : ('a list of (blockid, (r, g, b)) tuples for coloring minerals', None), } +class Hide(RenderPrimitive): + name = "hide" + options = { + 'blocks' : ('a list of blockids or (blockid, data) tuples of blocks to hide', []), + } + # Built-in rendermodes for your convenience! normal = [Base(), EdgeLines()] lighting = [Base(), EdgeLines(), Lighting()] diff --git a/overviewer_core/src/primitives/hide.c b/overviewer_core/src/primitives/hide.c new file mode 100644 index 0000000..5444e82 --- /dev/null +++ b/overviewer_core/src/primitives/hide.c @@ -0,0 +1,111 @@ +/* + * This file is part of the Minecraft Overviewer. + * + * Minecraft Overviewer is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Minecraft Overviewer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the Overviewer. If not, see . + */ + +#include "../overviewer.h" + +struct HideRule { + unsigned short blockid; + unsigned char has_data; + unsigned char data; +}; + +typedef struct { + struct HideRule* rules; +} RenderPrimitiveHide; + +static int +hide_start(void *data, RenderState *state, PyObject *support) { + PyObject *opt; + RenderPrimitiveHide* self = (RenderPrimitiveHide *)data; + self->rules = NULL; + + if (!render_mode_parse_option(support, "blocks", "O", &(opt))) + return 1; + if (opt && opt != Py_None) { + Py_ssize_t blocks_size = 0, i; + + if (!PyList_Check(opt)) { + PyErr_SetString(PyExc_TypeError, "'blocks' must be a list"); + return 1; + } + + blocks_size = PyList_GET_SIZE(opt); + self->rules = calloc(blocks_size + 1, sizeof(struct HideRule)); + if (self->rules == NULL) { + return 1; + } + + for (i = 0; i < blocks_size; i++) { + PyObject *block = PyList_GET_ITEM(opt, i); + + if (PyInt_Check(block)) { + /* format 1: just a block id */ + self->rules[i].blockid = PyInt_AsLong(block); + self->rules[i].has_data = 0; + } else if (PyArg_ParseTuple(block, "Hb", &(self->rules[i].blockid), &(self->rules[i].data))) { + /* format 2: (blockid, data) */ + self->rules[i].has_data = 1; + } else { + /* format not recognized */ + free(self->rules); + self->rules = NULL; + return 1; + } + } + } + + return 0; +} + +static void +hide_finish(void *data, RenderState *state) { + RenderPrimitiveHide *self = (RenderPrimitiveHide *)data; + + if (self->rules) { + free(self->rules); + } +} + +static int +hide_hidden(void *data, RenderState *state, int x, int y, int z) { + RenderPrimitiveHide *self = (RenderPrimitiveHide *)data; + unsigned int i; + + if (self->rules == NULL) + return 0; + + for (i = 0; self->rules[i].blockid != 0; i++) { + if (state->block == self->rules[i].blockid) { + if (!(self->rules[i].has_data)) + return 1; + if (state->block_data == self->rules[i].data) + return 1; + } + } + + return 0; +} + +RenderPrimitiveInterface primitive_hide = { + "hide", + sizeof(RenderPrimitiveHide), + hide_start, + hide_finish, + NULL, + hide_hidden, + NULL, +}; From 838bd2e5abf829357164433f4aeddf5489f26ac5 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 12 Apr 2012 15:33:24 -0400 Subject: [PATCH 18/85] fixed Hide() primitive and made EdgeLines() play nice --- overviewer_core/src/overviewer.h | 2 +- overviewer_core/src/primitives/edge-lines.c | 9 +++++---- overviewer_core/src/primitives/hide.c | 10 ++++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index 1bb8f92..c9b7ae6 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 30 +#define OVERVIEWER_EXTENSION_VERSION 31 /* Python PIL, and numpy headers */ #include diff --git a/overviewer_core/src/primitives/edge-lines.c b/overviewer_core/src/primitives/edge-lines.c index dc3d1c1..00f12ae 100644 --- a/overviewer_core/src/primitives/edge-lines.c +++ b/overviewer_core/src/primitives/edge-lines.c @@ -38,6 +38,7 @@ edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, P Imaging img_i = imaging_python_to_c(state->img); unsigned char ink[] = {0, 0, 0, 255 * self->opacity}; unsigned short side_block; + int x = state->x, y = state->y, z = state->z; int increment=0; if (state->block == 44 && ((state->block_data & 0x8) == 0 )) // half-step BUT no upsidown half-step @@ -46,15 +47,15 @@ edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, P increment=9; /* +X side */ - side_block = get_data(state, BLOCKS, state->x+1, state->y, state->z); - if (side_block != state->block && is_transparent(side_block)) { + side_block = get_data(state, BLOCKS, x+1, y, z); + if (side_block != state->block && (is_transparent(side_block) || render_mode_hidden(state->rendermode, x+1, y, z))) { ImagingDrawLine(img_i, state->imgx+12, state->imgy+1+increment, state->imgx+22+1, state->imgy+5+1+increment, &ink, 1); ImagingDrawLine(img_i, state->imgx+12, state->imgy+increment, state->imgx+22+1, state->imgy+5+increment, &ink, 1); } /* -Z side */ - side_block = get_data(state, BLOCKS, state->x, state->y, state->z-1); - if (side_block != state->block && is_transparent(side_block)) { + side_block = get_data(state, BLOCKS, x, y, z-1); + if (side_block != state->block && (is_transparent(side_block) || render_mode_hidden(state->rendermode, x, y, z-1))) { ImagingDrawLine(img_i, state->imgx, state->imgy+6+1+increment, state->imgx+12+1, state->imgy+1+increment, &ink, 1); ImagingDrawLine(img_i, state->imgx, state->imgy+6+increment, state->imgx+12+1, state->imgy+increment, &ink, 1); } diff --git a/overviewer_core/src/primitives/hide.c b/overviewer_core/src/primitives/hide.c index 5444e82..cdb24e8 100644 --- a/overviewer_core/src/primitives/hide.c +++ b/overviewer_core/src/primitives/hide.c @@ -84,15 +84,21 @@ static int hide_hidden(void *data, RenderState *state, int x, int y, int z) { RenderPrimitiveHide *self = (RenderPrimitiveHide *)data; unsigned int i; + unsigned short block; if (self->rules == NULL) return 0; + block = get_data(state, BLOCKS, x, y, z); for (i = 0; self->rules[i].blockid != 0; i++) { - if (state->block == self->rules[i].blockid) { + if (block == self->rules[i].blockid) { + unsigned char data; + if (!(self->rules[i].has_data)) return 1; - if (state->block_data == self->rules[i].data) + + data = get_data(state, DATA, x, y, z); + if (data == self->rules[i].data) return 1; } } From 85e2ac202fad83e3ddd1a06a9fc43cab5146b0f9 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Fri, 13 Apr 2012 23:48:07 -0400 Subject: [PATCH 19/85] Fix overlay code so that overlays with no 'overlay' config are always displayed --- overviewer_core/data/js_src/views.js | 46 +++++++++++++++------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 21fbaac..ccff3bf 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -269,29 +269,31 @@ overviewer.views.OverlayControlView = Backbone.View.extend({ for (i in mapTypes) { var mt = mapTypes[i]; - if (mt.tiles.indexOf(currentTileSetPath)!=-1) { - this.addItem({label: mt.name, - name: mt.name, - mt: mt, - - action: function(this_item, checked) { - if (checked) { - overviewer.map.overlayMapTypes.push(this_item.mt); - } else { - var idx_to_delete = -1; - overviewer.map.overlayMapTypes.forEach(function(e, j) { - if (e == this_item.mt) { - idx_to_delete = j; - } - }); - if (idx_to_delete >= 0) { - overviewer.map.overlayMapTypes.removeAt(idx_to_delete); - } - } - - } - }) + // if this overlay specifies a list of valid tilesets, then skip over any invalid tilesets + if ((mt.tiles.length > 0) && (mt.tiles.indexOf(currentTileSetPath) ==-1)) { + continue; } + this.addItem({label: mt.name, + name: mt.name, + mt: mt, + + action: function(this_item, checked) { + if (checked) { + overviewer.map.overlayMapTypes.push(this_item.mt); + } else { + var idx_to_delete = -1; + overviewer.map.overlayMapTypes.forEach(function(e, j) { + if (e == this_item.mt) { + idx_to_delete = j; + } + }); + if (idx_to_delete >= 0) { + overviewer.map.overlayMapTypes.removeAt(idx_to_delete); + } + } + + } + }); } From 2a6769c5ac865b843a5b8483a5b333ea08dd6f18 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 14 Apr 2012 22:09:12 -0400 Subject: [PATCH 20/85] Revised syntax/method for specifying POIs --- docs/signs.rst | 50 +++++++++++++++++---------- genPOI.py | 26 +++++++++----- overviewer_core/data/js_src/views.js | 7 ++-- overviewer_core/settingsValidators.py | 8 +++-- 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/docs/signs.rst b/docs/signs.rst index d10e755..efa0514 100644 --- a/docs/signs.rst +++ b/docs/signs.rst @@ -20,32 +20,30 @@ Filter Functions ---------------- A filter function is a python function that is used to figure out if a given POI -should be part of a markerSet of not. The function should accept one argument -(a dictionary, also know as an associative array), and return a boolean:: +should be part of a markerSet of not, and to control how it is displayed. +The function should accept one argument (a dictionary, also know as an associative +array), and return a string representing the text to be displayed. For example:: def signFilter(poi): - "All signs" - return poi['id'] == 'Sign' + if poi['id'] == 'Sign': + return "\n".join([poi['Text1'], poi['Text2'], poi['Text3'], poi['Text4']]) + +If a POI doesn't match, the filter can return None (which is the default if a python +functions runs off the end without an explicit 'return'). The single argument will either a TileEntity, or an Entity taken directly from -the chunk file. In this example, this function returns true only if the type -of entity is a sign. For more information of TileEntities and Entities, see +the chunk file. In this example, this function returns all 4 lines from the sign +if the entity is a sign. +For more information of TileEntities and Entities, see the `Chunk Format `_ page on the Minecraft Wiki. -.. note:: - The doc string ("All signs" in this example) is important. It is the label - that appears in your rendered map +A more complicated filter function can construct a more customized display text:: -A more advanced filter may also look at other entity fields, such as the sign text:: + def chestFilter(poi): + if poi['id'] == "Chest": + return "Chest with %d items" % len(poi['Items']) - def goldFilter(poi): - "Gold" - return poi['id'] == 'Sign' and (\ - 'gold' in poi['Text1'] or - 'gold' in poi['Text2']) - -This looks for the word 'gold' in either the first or second line of the signtext. Since writing these filters can be a little tedious, a set of predefined filters functions are provided. See the :ref:`predefined_filter_functions` section for @@ -56,15 +54,29 @@ Render Dictionary Key Each render can specify a list of zero or more filter functions. Each of these filter functions become a selectable item in the 'Signs' drop-down menu in the -rendered map. For example:: +rendered map. Previously, this used to be a list of functions. Now it is a list +of dictionaries. For example:: renders['myrender'] = { 'world': 'myworld', 'title': "Example", - 'markers': [allFilter, anotherFilter], + 'markers': [dict(name="All signs", filterFunction=signFilter), + dict(name="Chests", filterFunction=chestFilter, icon="chest.png")] } +The following keys are accepted in the marker dictionary: + +``name`` + This is the text that is displayed in the 'Signs' dropdown. + +``filterFunction`` + This is the filter function. It must accept at least 1 argument (the POI to filter), + and it must return either None or a string. + +``icon`` + Optional. Specifies the icon to use for POIs in this group. If omitted, it defaults + to a signpost icon. Generating the POI Markers diff --git a/genPOI.py b/genPOI.py index 66a8360..b5c07d0 100755 --- a/genPOI.py +++ b/genPOI.py @@ -25,7 +25,8 @@ from overviewer_core import configParser, world def handleSigns(rset, outputdir, render, rname): - + + # if we're already handled the POIs for this region regionset, do nothing if hasattr(rset, "_pois"): return @@ -39,6 +40,7 @@ def handleSigns(rset, outputdir, render, rname): rset._pois['TileEntities'] += data['TileEntities'] rset._pois['Entities'] += data['Entities'] + print "Done." def main(): helptext = """genPOI @@ -97,13 +99,15 @@ def main(): return 1 for f in render['markers']: - markersets.add((f, rset)) - name = f.__name__ + hex(hash(f))[-4:] + "_" + hex(hash(rset))[-4:] + d = dict(icon="signpost_icon.png") + d.update(f) + markersets.add(((d['name'], d['filterFunction']), rset)) + name = f['name']+ hex(hash(f['filterFunction']))[-4:] + "_" + hex(hash(rset))[-4:] try: l = markers[rname] - l.append(dict(groupName=name, displayName = f.__doc__)) + l.append(dict(groupName=name, displayName = f['name'], icon=d['icon'])) except KeyError: - markers[rname] = [dict(groupName=name, displayName=f.__doc__),] + markers[rname] = [dict(groupName=name, displayName=f['name'], icon=d['icon']),] handleSigns(rset, os.path.join(destdir, rname), render, rname) @@ -112,11 +116,15 @@ def main(): markerSetDict = dict() for (flter, rset) in markersets: # generate a unique name for this markerset. it will not be user visible - name = flter.__name__ + hex(hash(flter))[-4:] + "_" + hex(hash(rset))[-4:] - markerSetDict[name] = dict(created=False, raw=[]) + filter_name = flter[0] + filter_function = flter[1] + + name = filter_name + hex(hash(filter_function))[-4:] + "_" + hex(hash(rset))[-4:] + markerSetDict[name] = dict(created=False, raw=[], name=filter_name) for poi in rset._pois['TileEntities']: - if flter(poi): - markerSetDict[name]['raw'].append(poi) + result = filter_function(poi) + if result: + markerSetDict[name]['raw'].append(dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True)) #print markerSetDict with open(os.path.join(destdir, "markersDB.js"), "w") as output: diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index ccff3bf..7e8a572 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -430,7 +430,6 @@ overviewer.views.SignControlView = Backbone.View.extend({ }}); } - iconURL = overviewerConfig.CONST.image.signMarker; //dataRoot['markers'] = []; // for (i in dataRoot) { @@ -442,11 +441,11 @@ overviewer.views.SignControlView = Backbone.View.extend({ 'position': overviewer.util.fromWorldToLatLng(entity.x, entity.y, entity.z, overviewer.mapView.options.currentTileSet), 'map': overviewer.map, - 'title': jQuery.trim(entity.Text1 + "\n" + entity.Text2 + "\n" + entity.Text3 + "\n" + entity.Text4), - 'icon': iconURL, + 'title': jQuery.trim(entity.text), + 'icon': dataRoot[i].icon, 'visible': false }); - if (entity['id'] == 'Sign') { + if (entity.createInfoWindow) { overviewer.util.createMarkerInfoWindow(marker); } jQuery.extend(entity, {markerObj: marker}); diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index 227f4d3..a0ba51e 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -47,8 +47,12 @@ def validateMarkers(filterlist): if type(filterlist) != list: raise ValidationException("Markers must specify a list of filters") for x in filterlist: - if not callable(x): - raise ValidationException("%r must be a function"% x) + if "name" not in x: + raise ValidationException("Must define a name") + if "filterFunction" not in x: + raise ValidationException("Must define a filter function") + if not callable(x['filterFunction']): + raise ValidationException("%r must be a function"% x['filterFunction']) return filterlist def validateOverlays(renderlist): From c583a94d7d7ea24646d355802084bfdf845c5f50 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sat, 14 Apr 2012 23:36:52 -0400 Subject: [PATCH 21/85] Update JonnyJD's pullrequest to work with the new POI codes Also: only parse players in a regionset once ignore corrupt player.dat files --- genPOI.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/genPOI.py b/genPOI.py index 8e358db..b2aa442 100755 --- a/genPOI.py +++ b/genPOI.py @@ -45,6 +45,10 @@ def handleSigns(rset, outputdir, render, rname): def handlePlayers(rset, render, worldpath): if not hasattr(rset, "_pois"): rset._pois = dict(TileEntities=[], Entities=[]) + + # only handle this region set once + if 'Players' in rset._pois: + return dimension = {'overworld': 0, 'nether': -1, 'end': 1, @@ -52,7 +56,11 @@ def handlePlayers(rset, render, worldpath): playerdir = os.path.join(worldpath, "players") rset._pois['Players'] = [] for playerfile in os.listdir(playerdir): - data = nbt.load(os.path.join(playerdir, playerfile))[1] + try: + data = nbt.load(os.path.join(playerdir, playerfile))[1] + except IOError: + logging.warning("Skipping bad player dat file %r", playerfile) + continue playername = playerfile.split(".")[0] if data['Dimension'] == dimension: # Position at last logout @@ -158,7 +166,7 @@ def main(): for poi in rset._pois['Players']: result = filter_function(poi) if result: - markerSetDict[name]['raw'].append(poi) + markerSetDict[name]['raw'].append(dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True)) #print markerSetDict with open(os.path.join(destdir, "markersDB.js"), "w") as output: From 44042c3d75d056a4b763d9730cdd2bfa150f462c Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Sun, 15 Apr 2012 14:23:48 +0100 Subject: [PATCH 22/85] Update usage information for genPOI Usage text update to include --quiet and reflect whether script is called independently or via the --genpoi flag for overviewer.py --- genPOI.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/genPOI.py b/genPOI.py index 66a8360..274f9e6 100755 --- a/genPOI.py +++ b/genPOI.py @@ -17,6 +17,7 @@ markers.js holds a list of which markerSets are attached to each tileSet import os import logging import json +import sys from optparse import OptionParser from overviewer_core import logger @@ -41,8 +42,13 @@ def handleSigns(rset, outputdir, render, rname): def main(): - helptext = """genPOI - %prog --config=""" + + if os.path.basename(sys.argv[0]) == """genPOI.py""": + helptext = """genPOI.py + %prog --config= [--quiet]""" + else: + helptext = """genPOI + %prog --genpoi --config= [--quiet]""" logger.configure() From 07bdf2aa93a985a5cb979addbf7b3c4a84642c36 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 15 Apr 2012 11:12:16 -0400 Subject: [PATCH 23/85] Handle spaces in filter names --- genPOI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/genPOI.py b/genPOI.py index 0d94fb7..800c8f5 100755 --- a/genPOI.py +++ b/genPOI.py @@ -145,7 +145,7 @@ def main(): d = dict(icon="signpost_icon.png") d.update(f) markersets.add(((d['name'], d['filterFunction']), rset)) - name = f['name']+ hex(hash(f['filterFunction']))[-4:] + "_" + hex(hash(rset))[-4:] + name = f['name'].replace(" ","_") + hex(hash(f['filterFunction']))[-4:] + "_" + hex(hash(rset))[-4:] try: l = markers[rname] l.append(dict(groupName=name, displayName = f['name'], icon=d['icon'])) @@ -163,7 +163,7 @@ def main(): filter_name = flter[0] filter_function = flter[1] - name = filter_name + hex(hash(filter_function))[-4:] + "_" + hex(hash(rset))[-4:] + name = filter_name.replace(" ","_") + hex(hash(filter_function))[-4:] + "_" + hex(hash(rset))[-4:] markerSetDict[name] = dict(created=False, raw=[], name=filter_name) for poi in rset._pois['TileEntities']: result = filter_function(poi) From 27acb575f7b029963130ebff4ec8c54bc3fc5137 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 15 Apr 2012 12:00:44 -0400 Subject: [PATCH 24/85] Allow filter functions to specify icons --- genPOI.py | 10 ++++++++-- overviewer_core/data/js_src/views.js | 13 ++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/genPOI.py b/genPOI.py index 800c8f5..650a2d6 100755 --- a/genPOI.py +++ b/genPOI.py @@ -168,11 +168,17 @@ def main(): for poi in rset._pois['TileEntities']: result = filter_function(poi) if result: - markerSetDict[name]['raw'].append(dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True)) + d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True) + if "icon" in poi: + d.update({"icon": poi['icon']}) + markerSetDict[name]['raw'].append(d) for poi in rset._pois['Players']: result = filter_function(poi) if result: - markerSetDict[name]['raw'].append(dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True)) + d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True) + if "icon" in poi: + d.update({"icon": poi['icon']}) + markerSetDict[name]['raw'].append(d) #print markerSetDict with open(os.path.join(destdir, "markersDB.js"), "w") as output: diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 041d2ba..2fde73d 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -437,22 +437,17 @@ overviewer.views.SignControlView = Backbone.View.extend({ if (!markersDB[groupName].created) { for (j in markersDB[groupName].raw) { var entity = markersDB[groupName].raw[j]; - if (entity['id'] == 'Player') { - iconURL = "http://overviewer.org/avatar/" - + entity['EntityId']; - } else if (entity['id'] == 'PlayerSpawn') { - iconURL = overviewerConfig.CONST.image.bedMarker; - } else if (entity['id'] == 'Sign') { - iconURL = overviewerConfig.CONST.image.signMarker; + if (entity['icon']) { + iconURL = entity['icon']; } else { - iconURL = overviewerConfig.CONST.image.defaultMarker; + iconURL = dataRoot[i].icon; } var marker = new google.maps.Marker({ 'position': overviewer.util.fromWorldToLatLng(entity.x, entity.y, entity.z, overviewer.mapView.options.currentTileSet), 'map': overviewer.map, 'title': jQuery.trim(entity.text), - 'icon': dataRoot[i].icon, + 'icon': iconURL, 'visible': false }); if (entity.createInfoWindow) { From 24f360882dc1bd5ef167e3ff89addc9e537f1bd6 Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Sun, 15 Apr 2012 18:42:01 +0100 Subject: [PATCH 25/85] Improve support for player POIs on single player worlds --- genPOI.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/genPOI.py b/genPOI.py index 650a2d6..07af4c9 100755 --- a/genPOI.py +++ b/genPOI.py @@ -41,7 +41,7 @@ def handleSigns(rset, outputdir, render, rname): rset._pois['TileEntities'] += data['TileEntities'] rset._pois['Entities'] += data['Entities'] - print "Done." + logging.info("Done.") def handlePlayers(rset, render, worldpath): if not hasattr(rset, "_pois"): @@ -55,14 +55,25 @@ def handlePlayers(rset, render, worldpath): 'end': 1, 'default': 0}[render['dimension']] playerdir = os.path.join(worldpath, "players") + if os.path.isdir(playerdir): + playerfiles = os.listdir(playerdir) + isSinglePlayer = False + else: + playerfiles = [os.path.join(worldpath, "level.dat")] + isSinglePlayer = True + rset._pois['Players'] = [] - for playerfile in os.listdir(playerdir): + for playerfile in playerfiles: try: data = nbt.load(os.path.join(playerdir, playerfile))[1] + if isSinglePlayer: + data = data['Data']['Player'] except IOError: logging.warning("Skipping bad player dat file %r", playerfile) continue playername = playerfile.split(".")[0] + if isSinglePlayer: + playername = 'Player' if data['Dimension'] == dimension: # Position at last logout data['id'] = "Player" From b0dbad4d7029087a409eafdea21a13e7852b29f7 Mon Sep 17 00:00:00 2001 From: Thomas Lake Date: Sun, 15 Apr 2012 19:10:04 +0100 Subject: [PATCH 26/85] Fix tab/spacing issues in previous commit --- genPOI.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/genPOI.py b/genPOI.py index 07af4c9..9b80a60 100755 --- a/genPOI.py +++ b/genPOI.py @@ -57,10 +57,10 @@ def handlePlayers(rset, render, worldpath): playerdir = os.path.join(worldpath, "players") if os.path.isdir(playerdir): playerfiles = os.listdir(playerdir) - isSinglePlayer = False + isSinglePlayer = False else: playerfiles = [os.path.join(worldpath, "level.dat")] - isSinglePlayer = True + isSinglePlayer = True rset._pois['Players'] = [] for playerfile in playerfiles: @@ -72,7 +72,7 @@ def handlePlayers(rset, render, worldpath): logging.warning("Skipping bad player dat file %r", playerfile) continue playername = playerfile.split(".")[0] - if isSinglePlayer: + if isSinglePlayer: playername = 'Player' if data['Dimension'] == dimension: # Position at last logout From 419daa3881817536b9795fc0d65c4ff2c7b55fee Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Tue, 17 Apr 2012 16:15:55 -0700 Subject: [PATCH 27/85] Update Contributors list --- CONTRIBUTORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index fb514d5..f128059 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -58,6 +58,7 @@ feature. * Maciej Malecki * Ryan McCue * Morlok8k + * Richard Pastrick * Ryan Rector * Jason Scheirer * Gregory Short From d573631e11c5c68d795e716d5734b64cb8979c93 Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Thu, 19 Apr 2012 01:44:15 +0200 Subject: [PATCH 28/85] add script to check for new contributors to list Use git shortlog to create a list of contributors that are not yet included in CONTRIBUTORS.rst The email address is taken as definitive. People with the same name, but different email addresses are supported. Aliases, different email addresses for the same person, are handled by git with .mailmap --- .mailmap | 2 ++ contrib/contributors.py | 51 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 .mailmap create mode 100755 contrib/contributors.py diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..78b378e --- /dev/null +++ b/.mailmap @@ -0,0 +1,2 @@ +Andrew Brown +Alex Headley diff --git a/contrib/contributors.py b/contrib/contributors.py new file mode 100755 index 0000000..9e97d22 --- /dev/null +++ b/contrib/contributors.py @@ -0,0 +1,51 @@ +#!/usr/bin/python2 +"""List contributors that are not yet in the contributor list + +Alias handling is done by git with .mailmap +""" + +import sys +from subprocess import Popen, PIPE + +def main(): + if len(sys.argv) > 1: + branch = sys.argv[1] + else: + branch = "master" + + contributors=[] + p_git = Popen(["git", "shortlog", "-se", branch], stdout=PIPE) + for line in p_git.stdout: + contributors.append({ + 'count': int(line.split("\t")[0].strip()), + 'name': line.split("\t")[1].split()[0:-1], + 'email': line.split("\t")[1].split()[-1] + }) + + old_contributors=[] + with open("CONTRIBUTORS.rst", "r") as contrib_file: + for line in contrib_file: + if "@" in line: + old_contributors.append({ + 'name': line.split()[1:-1], + 'email': line.split()[-1] + }) + # We don't access the name of old/listed contributors at all + # but that might change. + # So we parse it anyways and strip it off again. + old_emails = map(lambda x: x['email'], old_contributors) + + new_contributors=[] + for contributor in contributors: + if contributor["email"] not in old_emails: + new_contributors.append(contributor) + + # sort on the last word of the name + new_contributors = sorted(new_contributors, + key=lambda x: x['name'][-1].lower()) + for contributor in new_contributors: + print "{0:3d} {1:25s} {2}".format(contributor["count"], + " ".join(contributor["name"]), contributor["email"]) + +if __name__ == "__main__": + main() From 1a26af6ebb69a1d9888be20d5a24fff39bfade92 Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Thu, 19 Apr 2012 02:57:13 +0200 Subject: [PATCH 29/85] script to update contributor list automatically The script merges new contributors in the short-term contributor list in CONTRIBUTORS.rst --- contrib/contributors.py | 51 +++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/contrib/contributors.py b/contrib/contributors.py index 9e97d22..4db8241 100755 --- a/contrib/contributors.py +++ b/contrib/contributors.py @@ -1,20 +1,24 @@ #!/usr/bin/python2 -"""List contributors that are not yet in the contributor list +"""Update the contributor list Alias handling is done by git with .mailmap +New contributors are merged in the short-term list. +Moving them to a "higher" list should be a manual process. """ -import sys +import fileinput from subprocess import Popen, PIPE -def main(): - if len(sys.argv) > 1: - branch = sys.argv[1] - else: - branch = "master" +def format_contributor(contributor): + return " * {0} {1}".format( + " ".join(contributor["name"]), + contributor["email"]) + +def main(): + # generate list of contributors contributors=[] - p_git = Popen(["git", "shortlog", "-se", branch], stdout=PIPE) + p_git = Popen(["git", "shortlog", "-se"], stdout=PIPE) for line in p_git.stdout: contributors.append({ 'count': int(line.split("\t")[0].strip()), @@ -22,6 +26,7 @@ def main(): 'email': line.split("\t")[1].split()[-1] }) + # cache listed contributors old_contributors=[] with open("CONTRIBUTORS.rst", "r") as contrib_file: for line in contrib_file: @@ -35,6 +40,7 @@ def main(): # So we parse it anyways and strip it off again. old_emails = map(lambda x: x['email'], old_contributors) + # check which contributors are new new_contributors=[] for contributor in contributors: if contributor["email"] not in old_emails: @@ -43,9 +49,34 @@ def main(): # sort on the last word of the name new_contributors = sorted(new_contributors, key=lambda x: x['name'][-1].lower()) + + # show new contributors to be merged to the list for contributor in new_contributors: - print "{0:3d} {1:25s} {2}".format(contributor["count"], - " ".join(contributor["name"]), contributor["email"]) + print format_contributor(contributor) + + # merge with contributor list + i = 0 + short_term_found = False + for line in fileinput.input("CONTRIBUTORS.rst", inplace=1): + if not short_term_found: + print line, + if "Short-term" in line: + short_term_found = True + else: + if i >= len(new_contributors) or "@" not in line: + print line, + else: + contributor = new_contributors[i] + if line.split()[-2] > contributor["name"][-1]: + print format_contributor(contributor) + i += 1 + print line, + # append remaining contributors + with open("CONTRIBUTORS.rst", "a") as contrib_file: + while i < len(new_contributors): + contrib_file.write(format_contributor(new_contributors[i]) + "\n") + i += 1 + if __name__ == "__main__": main() From 3f93dc4b6dea2c4ee93e98c546907d4e67642769 Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Thu, 19 Apr 2012 16:58:11 +0200 Subject: [PATCH 30/85] handle all types of aliases for the contributor list If a contributor email is already in the list we won't create a new entry. However, if the name is different than in the list, we print a message if an alias is missing in .mailmap If an email is not in the list, but the name is in the list this could mean two things: 1. Two different persons have the same name. This is possible, but less likely than 2. 2. A contributor used another mail. This is likely the case and we don't make a new entry, but print a message. --- .mailmap | 3 +++ contrib/contributors.py | 46 +++++++++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/.mailmap b/.mailmap index 78b378e..23cdf70 100644 --- a/.mailmap +++ b/.mailmap @@ -1,2 +1,5 @@ Andrew Brown Alex Headley +Alex Headley aheadley +Michael Fallows redorkulated +Maciej Malecki Maciej Małecki diff --git a/contrib/contributors.py b/contrib/contributors.py index 4db8241..a066b74 100755 --- a/contrib/contributors.py +++ b/contrib/contributors.py @@ -17,7 +17,7 @@ def format_contributor(contributor): def main(): # generate list of contributors - contributors=[] + contributors = [] p_git = Popen(["git", "shortlog", "-se"], stdout=PIPE) for line in p_git.stdout: contributors.append({ @@ -27,7 +27,7 @@ def main(): }) # cache listed contributors - old_contributors=[] + old_contributors = [] with open("CONTRIBUTORS.rst", "r") as contrib_file: for line in contrib_file: if "@" in line: @@ -35,24 +35,52 @@ def main(): 'name': line.split()[1:-1], 'email': line.split()[-1] }) - # We don't access the name of old/listed contributors at all - # but that might change. - # So we parse it anyways and strip it off again. + + old = map(lambda x: (x['name'], x['email']), old_contributors) old_emails = map(lambda x: x['email'], old_contributors) + old_names = map(lambda x: x['name'], old_contributors) # check which contributors are new - new_contributors=[] + new_contributors = [] + update_mailmap = False for contributor in contributors: - if contributor["email"] not in old_emails: + if (contributor['name'], contributor['email']) in old: + # this exact combination already in the list + pass + elif (contributor['email'] not in old_emails + and contributor['name'] not in old_names): + # name AND email are not in the list new_contributors.append(contributor) + elif contributor['email'] in old_emails: + # email is listed, but with another name + old_name = filter(lambda x: x['email'] == contributor['email'], + old_contributors)[0]['name'] + print "new alias %s for %s %s ?" % ( + " ".join(contributor['name']), + " ".join(old_name), + contributor['email']) + update_mailmap = True + elif contributor['name'] in old_names: + # probably a new email for a previous contributor + other_mail = filter(lambda x: x['name'] == contributor['name'], + old_contributors)[0]['email'] + print "new email %s for %s %s ?" % ( + contributor['email'], + " ".join(contributor['name']), + other_mail) + update_mailmap = True + if update_mailmap: + print "Please update .mailmap" # sort on the last word of the name new_contributors = sorted(new_contributors, key=lambda x: x['name'][-1].lower()) # show new contributors to be merged to the list - for contributor in new_contributors: - print format_contributor(contributor) + if new_contributors: + print "inserting:" + for contributor in new_contributors: + print format_contributor(contributor) # merge with contributor list i = 0 From 4f6f831456bc4b91be6a36d9fa9bcbb0e6c3d663 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Thu, 19 Apr 2012 20:02:34 -0400 Subject: [PATCH 31/85] Updated contributors list --- CONTRIBUTORS.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index fb514d5..4f71190 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -39,28 +39,45 @@ Short-term Contributions These contributors have made specific changes for a particular bug fix or feature. + * Albireo * arrai * Kyle Brantley + * asmodai * but2002 + * Mark Barnes * Eric Carr + * Carter Charbonneau * cbarber * Alex Cline * Andrew Clunis * CounterPillow + * Johannes Dewender * Michael Fallows + * Ryan Finnie * Stephen Fluin + * Pierre Guinoiseau * Benjamin Herr + * Lucas Hereld * Ryan Hitchman * Jenny * Michael Jensen + * Sean Kilgore * Johan Kiviniemi + * Philip Kovac * Thomas Lake * Maciej Malecki * Ryan McCue + * Zach McCullough * Morlok8k + * Mike * Ryan Rector + * Richard Pastrick * Jason Scheirer * Gregory Short * Sam Steele + * stoneLeaf * timwolla + * TJ09 * Jeffrey Warren + * untergrundbiber + * Philippe Villiers From f6dcfea6fe0198c5afb7494c94d86ab53b8fe8a6 Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Fri, 20 Apr 2012 11:53:59 +0200 Subject: [PATCH 32/85] fix contributor list sorting Two things were off: 1. sorting should be case-insensitive, in both places 2. multiple entries can be added just before the same line --- CONTRIBUTORS.rst | 14 +++++++------- contrib/contributors.py | 10 ++++++++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 4f71190..ff8eb83 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -41,13 +41,13 @@ feature. * Albireo * arrai - * Kyle Brantley * asmodai - * but2002 * Mark Barnes + * Kyle Brantley + * but2002 * Eric Carr - * Carter Charbonneau * cbarber + * Carter Charbonneau * Alex Cline * Andrew Clunis * CounterPillow @@ -56,8 +56,8 @@ feature. * Ryan Finnie * Stephen Fluin * Pierre Guinoiseau - * Benjamin Herr * Lucas Hereld + * Benjamin Herr * Ryan Hitchman * Jenny * Michael Jensen @@ -68,16 +68,16 @@ feature. * Maciej Malecki * Ryan McCue * Zach McCullough - * Morlok8k * Mike - * Ryan Rector + * Morlok8k * Richard Pastrick + * Ryan Rector * Jason Scheirer * Gregory Short * Sam Steele * stoneLeaf * timwolla * TJ09 - * Jeffrey Warren * untergrundbiber * Philippe Villiers + * Jeffrey Warren diff --git a/contrib/contributors.py b/contrib/contributors.py index a066b74..73ee45b 100755 --- a/contrib/contributors.py +++ b/contrib/contributors.py @@ -82,7 +82,7 @@ def main(): for contributor in new_contributors: print format_contributor(contributor) - # merge with contributor list + # merge with alphabetical (by last part of name) contributor list i = 0 short_term_found = False for line in fileinput.input("CONTRIBUTORS.rst", inplace=1): @@ -94,10 +94,16 @@ def main(): if i >= len(new_contributors) or "@" not in line: print line, else: + listed_name = line.split()[-2].lower() contributor = new_contributors[i] - if line.split()[-2] > contributor["name"][-1]: + # insert all new contributors that fit here + while listed_name > contributor["name"][-1].lower(): print format_contributor(contributor) i += 1 + if i < len(new_contributors): + contributor = new_contributors[i] + else: + break print line, # append remaining contributors with open("CONTRIBUTORS.rst", "a") as contrib_file: From 5184c8d3212f7e4850adfb4ab0c784a368f9113a Mon Sep 17 00:00:00 2001 From: Adam Novak Date: Tue, 24 Apr 2012 17:04:51 -0700 Subject: [PATCH 33/85] Added and documented the "exposed" render mode primitive. --- CONTRIBUTORS.rst | 1 + docs/config.rst | 8 +++ overviewer_core/rendermodes.py | 6 ++ overviewer_core/src/primitives/exposed.c | 91 ++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 overviewer_core/src/primitives/exposed.c diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index ff8eb83..6c8da67 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -69,6 +69,7 @@ feature. * Ryan McCue * Zach McCullough * Mike + * Adam Novak * Morlok8k * Richard Pastrick * Ryan Rector diff --git a/docs/config.rst b/docs/config.rst index 042ae0d..ef4dbed 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -611,6 +611,14 @@ Depth max highest level of blocks to render. Default: 255 +Exposed + Only renders blocks that are exposed (adjacent to a transparent block). + + **Options** + + mode + when set to 1, inverts the render mode, only drawing unexposed blocks. Default: 0 + EdgeLines Draw edge lines on the back side of blocks, to help distinguish them from the background. diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py index e1adc9c..2f5d3c8 100644 --- a/overviewer_core/rendermodes.py +++ b/overviewer_core/rendermodes.py @@ -62,6 +62,12 @@ class Depth(RenderPrimitive): "min": ("lowest level of blocks to render", 0), "max": ("highest level of blocks to render", 255), } + +class Exposed(RenderPrimitive): + name = "exposed" + options = { + "mode": ("0 = exposed blocks only, 1 = unexposed blocks only", 0), + } class EdgeLines(RenderPrimitive): name = "edge-lines" diff --git a/overviewer_core/src/primitives/exposed.c b/overviewer_core/src/primitives/exposed.c new file mode 100644 index 0000000..d05ac66 --- /dev/null +++ b/overviewer_core/src/primitives/exposed.c @@ -0,0 +1,91 @@ +/* + * This file is part of the Minecraft Overviewer. + * + * Minecraft Overviewer is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Minecraft Overviewer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the Overviewer. If not, see . + */ + +#include "../overviewer.h" + +typedef struct { + unsigned int mode; /* 0 = exposed only, 1 = unexposed only */ +} PrimitiveExposed; + +static int +exposed_start(void *data, RenderState *state, PyObject *support) { + PrimitiveExposed *self = (PrimitiveExposed *)data; + + if (!render_mode_parse_option(support, "mode", "I", &(self->mode))) + return 1; + + return 0; +} + +static int +exposed_hidden(void *data, RenderState *state, int x, int y, int z) { + PrimitiveExposed *self = (PrimitiveExposed *)data; + + /* Unset these flags if seeming exposure from any of these directions would + * be due to not having data there. + */ + int validMinusX = 1; + int validPlusY = 1; + int validPlusZ = 1; + + /* special handling for section boundaries */ + /* If the neighboring section has no block data, ignore exposure from that + * direction + */ + if (x == 0 && (!(state->chunks[0][1].loaded) || state->chunks[0][1].sections[state->chunky].blocks == NULL)) { + /* No data in -x direction */ + validMinusX = 0; + } + + if (y == 15 && (state->chunky + 1 >= SECTIONS_PER_CHUNK || state->chunks[1][1].sections[state->chunky + 1].blocks == NULL)) { + /* No data in +y direction */ + validPlusY = 0; + } + + if (z == 15 && (!(state->chunks[1][2].loaded) || state->chunks[1][2].sections[state->chunky].blocks == NULL)) { + /* No data in +z direction */ + validPlusZ = 0; + } + + /* If any of the 6 blocks adjacent to us are transparent, we're exposed */ + if( (validMinusX && is_transparent(get_data(state, BLOCKS, x-1, y, z))) || + is_transparent(get_data(state, BLOCKS, x+1, y, z)) || + is_transparent(get_data(state, BLOCKS, x, y-1, z)) || + (validPlusY && is_transparent(get_data(state, BLOCKS, x, y+1, z))) || + is_transparent(get_data(state, BLOCKS, x, y, z-1)) || + (validPlusZ && is_transparent(get_data(state, BLOCKS, x, y, z+1 ))) ) { + + /* Block is exposed */ + /* Returns 1 and hides us if we're rendering unexposed blocks, 0 and + * shows us if we're rendering exposed blocks + */ + return self->mode; + + } + + /* We have no valid evidence that the block is exposed */ + return !(self->mode); /* Hide in normal mode, reveal in inverted mode */ +} + +RenderPrimitiveInterface primitive_exposed = { + "exposed", sizeof(PrimitiveExposed), + exposed_start, + NULL, + NULL, + exposed_hidden, + NULL, +}; From 9df14462769eab275128a82fe30983ee3062e438 Mon Sep 17 00:00:00 2001 From: Adam Novak Date: Tue, 24 Apr 2012 20:29:27 -0700 Subject: [PATCH 34/85] Added a NoFluids render mode primitive, and documented it. --- docs/config.rst | 3 ++ overviewer_core/rendermodes.py | 3 ++ overviewer_core/src/primitives/no-fluids.c | 44 ++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 overviewer_core/src/primitives/no-fluids.c diff --git a/docs/config.rst b/docs/config.rst index ef4dbed..9bc38d8 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -618,6 +618,9 @@ Exposed mode when set to 1, inverts the render mode, only drawing unexposed blocks. Default: 0 + +NoFluids + Don't render fluid blocks (water, lava). EdgeLines Draw edge lines on the back side of blocks, to help distinguish them from diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py index 2f5d3c8..a161656 100644 --- a/overviewer_core/rendermodes.py +++ b/overviewer_core/rendermodes.py @@ -68,6 +68,9 @@ class Exposed(RenderPrimitive): options = { "mode": ("0 = exposed blocks only, 1 = unexposed blocks only", 0), } + +class NoFluids(RenderPrimitive): + name = "no-fluids" class EdgeLines(RenderPrimitive): name = "edge-lines" diff --git a/overviewer_core/src/primitives/no-fluids.c b/overviewer_core/src/primitives/no-fluids.c new file mode 100644 index 0000000..1f6cc16 --- /dev/null +++ b/overviewer_core/src/primitives/no-fluids.c @@ -0,0 +1,44 @@ +/* + * This file is part of the Minecraft Overviewer. + * + * Minecraft Overviewer is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Minecraft Overviewer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the Overviewer. If not, see . + */ + +#include "../overviewer.h" + +typedef struct { +} PrimitiveNoFluids; + +static int +no_fluids_start(void *data, RenderState *state, PyObject *support) { + PrimitiveNoFluids *self = (PrimitiveNoFluids *)data; + + return 0; +} + +static int +no_fluids_hidden(void *data, RenderState *state, int x, int y, int z) { + PrimitiveNoFluids *self = (PrimitiveNoFluids *)data; + + return !block_has_property(state->block, FLUID); +} + +RenderPrimitiveInterface primitive_no_fluids = { + "no-fluids", sizeof(PrimitiveNoFluids), + no_fluids_start, + NULL, + NULL, + no_fluids_hidden, + NULL, +}; From b1e4b09ab68bfb31e4cdf790ed9bcc3deffeb3d6 Mon Sep 17 00:00:00 2001 From: Adam Novak Date: Tue, 24 Apr 2012 20:35:00 -0700 Subject: [PATCH 35/85] Removing unused struct. --- overviewer_core/src/primitives/no-fluids.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/overviewer_core/src/primitives/no-fluids.c b/overviewer_core/src/primitives/no-fluids.c index 1f6cc16..fe1c704 100644 --- a/overviewer_core/src/primitives/no-fluids.c +++ b/overviewer_core/src/primitives/no-fluids.c @@ -17,25 +17,18 @@ #include "../overviewer.h" -typedef struct { -} PrimitiveNoFluids; - static int no_fluids_start(void *data, RenderState *state, PyObject *support) { - PrimitiveNoFluids *self = (PrimitiveNoFluids *)data; - return 0; } static int no_fluids_hidden(void *data, RenderState *state, int x, int y, int z) { - PrimitiveNoFluids *self = (PrimitiveNoFluids *)data; - return !block_has_property(state->block, FLUID); } RenderPrimitiveInterface primitive_no_fluids = { - "no-fluids", sizeof(PrimitiveNoFluids), + "no-fluids", 0, no_fluids_start, NULL, NULL, From 915aa1a653991f7469a995573a7de5bdc7e4ff47 Mon Sep 17 00:00:00 2001 From: Adam Novak Date: Tue, 24 Apr 2012 20:40:39 -0700 Subject: [PATCH 36/85] Inverting sense of no-fluids to be correct. --- overviewer_core/src/primitives/no-fluids.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/src/primitives/no-fluids.c b/overviewer_core/src/primitives/no-fluids.c index fe1c704..cb6428a 100644 --- a/overviewer_core/src/primitives/no-fluids.c +++ b/overviewer_core/src/primitives/no-fluids.c @@ -24,7 +24,7 @@ no_fluids_start(void *data, RenderState *state, PyObject *support) { static int no_fluids_hidden(void *data, RenderState *state, int x, int y, int z) { - return !block_has_property(state->block, FLUID); + return block_has_property(state->block, FLUID); } RenderPrimitiveInterface primitive_no_fluids = { From e0c4137eb49b4bfe3b07801e0a034c9109159a54 Mon Sep 17 00:00:00 2001 From: Adam Novak Date: Wed, 25 Apr 2012 00:02:20 -0700 Subject: [PATCH 37/85] Checking for missing data on all sides. --- overviewer_core/src/primitives/exposed.c | 26 ++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/overviewer_core/src/primitives/exposed.c b/overviewer_core/src/primitives/exposed.c index d05ac66..1047beb 100644 --- a/overviewer_core/src/primitives/exposed.c +++ b/overviewer_core/src/primitives/exposed.c @@ -39,7 +39,10 @@ exposed_hidden(void *data, RenderState *state, int x, int y, int z) { * be due to not having data there. */ int validMinusX = 1; + int validPlusX = 1; + int validMinusY = 1; int validPlusY = 1; + int validMinusZ = 1; int validPlusZ = 1; /* special handling for section boundaries */ @@ -50,12 +53,27 @@ exposed_hidden(void *data, RenderState *state, int x, int y, int z) { /* No data in -x direction */ validMinusX = 0; } + + if (x == 15 && (!(state->chunks[2][1].loaded) || state->chunks[2][1].sections[state->chunky].blocks == NULL)) { + /* No data in +x direction */ + validPlusX = 0; + } + + if (y == 0 && (state->chunky - 1 < 0 || state->chunks[1][1].sections[state->chunky - 1].blocks == NULL)) { + /* No data in -y direction */ + validMinusY = 0; + } if (y == 15 && (state->chunky + 1 >= SECTIONS_PER_CHUNK || state->chunks[1][1].sections[state->chunky + 1].blocks == NULL)) { /* No data in +y direction */ validPlusY = 0; } + if (z == 0 && (!(state->chunks[1][0].loaded) || state->chunks[1][0].sections[state->chunky].blocks == NULL)) { + /* No data in -z direction */ + validMinusZ = 0; + } + if (z == 15 && (!(state->chunks[1][2].loaded) || state->chunks[1][2].sections[state->chunky].blocks == NULL)) { /* No data in +z direction */ validPlusZ = 0; @@ -63,10 +81,10 @@ exposed_hidden(void *data, RenderState *state, int x, int y, int z) { /* If any of the 6 blocks adjacent to us are transparent, we're exposed */ if( (validMinusX && is_transparent(get_data(state, BLOCKS, x-1, y, z))) || - is_transparent(get_data(state, BLOCKS, x+1, y, z)) || - is_transparent(get_data(state, BLOCKS, x, y-1, z)) || - (validPlusY && is_transparent(get_data(state, BLOCKS, x, y+1, z))) || - is_transparent(get_data(state, BLOCKS, x, y, z-1)) || + (validPlusX && is_transparent(get_data(state, BLOCKS, x+1, y, z))) || + (validMinusY && is_transparent(get_data(state, BLOCKS, x, y-1, z))) || + (validPlusY && is_transparent(get_data(state, BLOCKS, x, y+1, z))) || + (validMinusZ && is_transparent(get_data(state, BLOCKS, x, y, z-1))) || (validPlusZ && is_transparent(get_data(state, BLOCKS, x, y, z+1 ))) ) { /* Block is exposed */ From 1f29ff5fa18ad2c1910c187259fa94d4c028d9fc Mon Sep 17 00:00:00 2001 From: Adam Novak Date: Wed, 25 Apr 2012 13:04:46 -0700 Subject: [PATCH 38/85] Fixed contributors ordering. --- CONTRIBUTORS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 6c8da67..4df9493 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -69,8 +69,8 @@ feature. * Ryan McCue * Zach McCullough * Mike - * Adam Novak * Morlok8k + * Adam Novak * Richard Pastrick * Ryan Rector * Jason Scheirer From 85567cae42854ce6232493fab66c161d313c5d92 Mon Sep 17 00:00:00 2001 From: Fabian Norman Date: Wed, 25 Apr 2012 19:42:18 -0700 Subject: [PATCH 39/85] Initial changes to add the base option to the config file. --- overviewer_core/settingsDefinition.py | 1 + overviewer_core/tileset.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index d2e357c..91c2e9b 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -80,6 +80,7 @@ renders = Setting(required=True, default=util.OrderedDict(), "changelist": Setting(required=False, validator=validateStr, default=None), "markers": Setting(required=False, validator=validateMarkers, default=[]), "showspawn": Setting(required=False, validator=validateBool, default=True), + "base": Setting(required=False, validator=validateStr, default=None), # Remove this eventually (once people update their configs) "worldname": Setting(required=False, default=None, diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index ab25a2a..4fa769f 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -513,7 +513,7 @@ class TileSet(object): defaultZoom = 1, maxZoom = self.treedepth, path = self.options.get('name'), - base = '', + base = self.options.get('base'), bgcolor = bgcolorformat(self.options.get('bgcolor')), world = self.options.get('worldname_orig') + (" - " + self.options.get('dimension') if self.options.get('dimension') != 'default' else ''), From d25f5824040c530685db1c33af8edffb3def9ea2 Mon Sep 17 00:00:00 2001 From: Fabian Norman Date: Wed, 25 Apr 2012 19:56:48 -0700 Subject: [PATCH 40/85] Base setting, one more change (last?) --- overviewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer.py b/overviewer.py index 986d59a..c31b51c 100755 --- a/overviewer.py +++ b/overviewer.py @@ -401,7 +401,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces. # only pass to the TileSet the options it really cares about render['name'] = render_name # perhaps a hack. This is stored here for the asset manager - tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist","showspawn"]) + tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist","showspawn","base"]) tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir) tilesets.append(tset) From 4fe87de247c5b2af9611f0756851540f078526ef Mon Sep 17 00:00:00 2001 From: Fabian Norman Date: Wed, 25 Apr 2012 23:42:19 -0700 Subject: [PATCH 41/85] Updated docs. --- docs/config.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/config.rst b/docs/config.rst index 042ae0d..fe97059 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -432,6 +432,13 @@ values. The valid configuration keys are listed below. **Default:** ``#1a1a1a`` +``base`` + Allows you to specify a remote location for the tile folder, useful if you + rsync your map's images to a remote server. Leave a trailing slash and point + to the location that contains the tile folders for each render, not the + tiles folder itself. For example, if the tile images start at + http://domain.com/map/world_day/ you want to set this to http://domain.com/map/ + .. _option_texture_pack: ``texturepath`` From 27c644d4ea66b09d4ab3f26c3bd21e0db32268fa Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Fri, 27 Apr 2012 09:19:31 -0700 Subject: [PATCH 42/85] Fix centering of the maps to the spawn point on first load --- overviewer_core/data/js_src/views.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 2fde73d..f3f2972 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -7,6 +7,14 @@ overviewer.views.WorldView = Backbone.View.extend({ this.options.overlayMapTypes = []; this.options.mapTypeIds = []; this.options.overlayMapTypeIds = []; + + var curTileSet = this.model.get("tileSets").at(0); + var spawn = curTileSet.get("spawn"); + if (spawn=="false") { + var spawn = [0,64,0]; + } + this.options.lastViewport = [spawn[0],spawn[1],spawn[2],curTileSet.get("defaultZoom")]; + this.model.get("tileSets").each(function(tset, index, list) { // ignore overlays: var ops = { @@ -139,17 +147,16 @@ overviewer.views.GoogleMapView = Backbone.View.extend({ var curWorld = this.model.get("currentWorldView").model; var curTset = curWorld.get("tileSets").at(0); + var spawn = curTset.get("spawn"); + if (spawn==false) { + var spawn = [0,64,0]; + } + var mapcenter = overviewer.util.fromWorldToLatLng( + spawn[0], + spawn[1], + spawn[2], + curTset); - /* - var defaultCenter = overviewer.util.fromWorldToLatLng( - overviewerConfig.map.center[0], - overviewerConfig.map.center[1], - overviewerConfig.map.center[2], - curTset.get("defaultZoom")); - */ - var lat = 0.62939453125;// TODO defaultCenter.lat(); - var lng = 0.38525390625; // TODO defaultCenter.lng(); - var mapcenter = new google.maps.LatLng(lat, lng); this.options.mapTypes=[]; this.options.mapTypeIds=[]; From 2ecb5dc9146fcbe40ff30a0e03ebcad005e6e61e Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Fri, 27 Apr 2012 09:22:41 -0700 Subject: [PATCH 43/85] Forgot quotes --- overviewer_core/data/js_src/views.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index f3f2972..3ca20c4 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -10,7 +10,7 @@ overviewer.views.WorldView = Backbone.View.extend({ var curTileSet = this.model.get("tileSets").at(0); var spawn = curTileSet.get("spawn"); - if (spawn=="false") { + if (spawn == "false") { var spawn = [0,64,0]; } this.options.lastViewport = [spawn[0],spawn[1],spawn[2],curTileSet.get("defaultZoom")]; @@ -148,7 +148,7 @@ overviewer.views.GoogleMapView = Backbone.View.extend({ var curTset = curWorld.get("tileSets").at(0); var spawn = curTset.get("spawn"); - if (spawn==false) { + if (spawn == "false") { var spawn = [0,64,0]; } var mapcenter = overviewer.util.fromWorldToLatLng( From c5af1c81fc41e858a4a718e9cad065fd071dc986 Mon Sep 17 00:00:00 2001 From: CounterPillow Date: Sun, 29 Apr 2012 02:26:14 +0200 Subject: [PATCH 44/85] Added a special case for the swamp biome. Addresses issue #708. --- overviewer_core/src/primitives/base.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/overviewer_core/src/primitives/base.c b/overviewer_core/src/primitives/base.c index 5a66a9a..ae93db7 100644 --- a/overviewer_core/src/primitives/base.c +++ b/overviewer_core/src/primitives/base.c @@ -206,6 +206,7 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec }; if (color_table) { + unsigned char biome; int dx, dz; unsigned char tablex, tabley; float temp = 0.0, rain = 0.0; @@ -215,7 +216,7 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec /* average over all neighbors */ for (dx = -1; dx <= 1; dx++) { for (dz = -1; dz <= 1; dz++) { - unsigned char biome = get_data(state, BIOMES, state->x + dx, state->y, state->z + dz); + biome = get_data(state, BIOMES, state->x + dx, state->y, state->z + dz); if (biome >= NUM_BIOMES) { /* note -- biome 255 shows up on map borders. who knows what it is? certainly not I. @@ -257,6 +258,18 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)); g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)); b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)); + + /* swamp hack + All values are guessed. They are probably somewhat odd or + completely wrong, but this looks okay for me, and I'm male, + so I can only distinct about 10 different colors anyways. + Blame my Y-Chromosone. */ + if(biome == 6) { + r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)) * 0.8; + g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)) / 2.0; + b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)) * 1.0; + } + Py_DECREF(color); } From 9508573783919acc6e51d589fcaaf65364c3cbeb Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 1 May 2012 20:31:50 -0400 Subject: [PATCH 45/85] Added hint about checking the docs on a bad markers validation --- overviewer_core/settingsValidators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index a0ba51e..0df90d1 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -45,7 +45,7 @@ def checkBadEscape(s): def validateMarkers(filterlist): if type(filterlist) != list: - raise ValidationException("Markers must specify a list of filters") + raise ValidationException("Markers must specify a list of filters. This has recently changed, so check the docs.") for x in filterlist: if "name" not in x: raise ValidationException("Must define a name") From 216b26cbf208a7adbc41252e923999c7f9afa7bd Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 1 May 2012 20:38:14 -0400 Subject: [PATCH 46/85] hide traceback on config validation failure a fully traceback is needlessly scary. use --verbose to see the traceback. --- overviewer.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/overviewer.py b/overviewer.py index 7b1226e..55400ce 100755 --- a/overviewer.py +++ b/overviewer.py @@ -246,8 +246,12 @@ dir but you forgot to put quotes around the directory, since it contains spaces. # Now parse and return the validated config try: config = mw_parser.get_validated_config() - except Exception: - logging.exception("An error was encountered with your configuration. See the info below.") + except Exception as ex: + if options.verbose: + logging.exception("An error was encountered with your configuration. See the info below.") + else: # no need to print scary traceback! just + logging.error("An error was encountered with your configuration.") + logging.error(str(ex)) return 1 From 6331200763255c54d6f9ffad3893e77fed2ae4f0 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Tue, 1 May 2012 21:40:53 -0400 Subject: [PATCH 47/85] More POI docs --- docs/signs.rst | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/docs/signs.rst b/docs/signs.rst index efa0514..415e581 100644 --- a/docs/signs.rst +++ b/docs/signs.rst @@ -32,7 +32,10 @@ If a POI doesn't match, the filter can return None (which is the default if a py functions runs off the end without an explicit 'return'). The single argument will either a TileEntity, or an Entity taken directly from -the chunk file. In this example, this function returns all 4 lines from the sign +the chunk file. It could also be a special entity representing a player's location +or a player's spawn. See below for more details. + +In this example, this function returns all 4 lines from the sign if the entity is a sign. For more information of TileEntities and Entities, see the `Chunk Format `_ page on @@ -49,6 +52,35 @@ Since writing these filters can be a little tedious, a set of predefined filters functions are provided. See the :ref:`predefined_filter_functions` section for details. + +Special POIs +------------ + +There are currently two special types of POIs. They each have a special id: + +PlayerSpawn + Used to indicate the spawn location of a player. The player's name is set + in the ``EntityId`` key, and the location is in the x,y,z keys + +Player + Used to indicate the last known location of a player. The player's name is set + in the ``EntityId`` key, and the location is in the x,y,z keys. + +.. note:: + The player location is taken from level.dat (in the case of a single-player world) + or the player.dat files (in the case of a multi-player server). The locations are + only written to these files when the world is saved, so this won't give you real-time + player location information. + +Here's an example that displays icons for each player:: + + def playerIcons(poi): + if poi['id'] == 'Player': + poi['icon'] = "http://overviewer.org/avatar/%s" % poi['EntityId'] + return "Last known location for %s" % poi['EntityId'] + +Note how each POI can get a different icon by setting ``poi['icon']`` + Render Dictionary Key --------------------- @@ -76,7 +108,9 @@ The following keys are accepted in the marker dictionary: ``icon`` Optional. Specifies the icon to use for POIs in this group. If omitted, it defaults - to a signpost icon. + to a signpost icon. Note that each POI can have different icon by setting the key 'icon' + on the POI itself (this can be done by modifying the POI in the filter function. See the + example above) Generating the POI Markers From e69717f476920a3a38b350c36bdfaaddc1d909c8 Mon Sep 17 00:00:00 2001 From: Fabian Norman Date: Wed, 2 May 2012 00:43:53 -0700 Subject: [PATCH 48/85] Prevent null being set in overviewerConfig.js --- overviewer_core/settingsDefinition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index 91c2e9b..44af092 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -80,7 +80,7 @@ renders = Setting(required=True, default=util.OrderedDict(), "changelist": Setting(required=False, validator=validateStr, default=None), "markers": Setting(required=False, validator=validateMarkers, default=[]), "showspawn": Setting(required=False, validator=validateBool, default=True), - "base": Setting(required=False, validator=validateStr, default=None), + "base": Setting(required=False, validator=validateStr, default=""), # Remove this eventually (once people update their configs) "worldname": Setting(required=False, default=None, From 59749199734a9d69717e3d9939ad5c8d9a7601b1 Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Tue, 1 May 2012 10:59:57 -0700 Subject: [PATCH 49/85] Make the rerenderprob value print a decent error since it does have to be between 0.0 and 1.0 instead of just that it is a float. Remove 0.0 and 1.0 as valid values --- overviewer_core/settingsDefinition.py | 2 +- overviewer_core/settingsValidators.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index 30c0c6e..413a285 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -75,7 +75,7 @@ renders = Setting(required=True, default=util.OrderedDict(), "nomarkers": Setting(required=False, validator=validateBool, default=None), "texturepath": Setting(required=False, validator=validateTexturePath, default=None), "renderchecks": Setting(required=False, validator=validateInt, default=None), - "rerenderprob": Setting(required=True, validator=validateFloat, default=0), + "rerenderprob": Setting(required=True, validator=validateRerenderprob, default=0), "crop": Setting(required=False, validator=validateCrop, default=None), "changelist": Setting(required=False, validator=validateStr, default=None), "markers": Setting(required=False, validator=validateMarkers, default=[]), diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index 0df90d1..aaf920e 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -111,10 +111,10 @@ def validateNorthDirection(direction): raise ValidationException("%r is not a valid north direction" % direction) return intdir -def validateStochastic(s): +def validateRerenderprob(s): val = float(s) - if val < 0 or val > 1: - raise ValidationException("%r is not a valid stochastic value. Should be between 0.0 and 1.0" % s) + if val =< 0 or val >= 1: + raise ValidationException("%r is not a valid rerender probability value. Should be between 0.0 and 1.0." % s) return val def validateImgFormat(fmt): From af8aa1361547f511c8047bb62f33bab350276178 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 2 May 2012 20:19:02 -0400 Subject: [PATCH 50/85] Fix typo in previous commit --- overviewer_core/settingsValidators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index aaf920e..f7745d2 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -113,7 +113,7 @@ def validateNorthDirection(direction): def validateRerenderprob(s): val = float(s) - if val =< 0 or val >= 1: + if val <= 0 or val >= 1: raise ValidationException("%r is not a valid rerender probability value. Should be between 0.0 and 1.0." % s) return val From da30592a45200955a1644f642de16d37fb8abf75 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 2 May 2012 20:25:23 -0400 Subject: [PATCH 51/85] Include the genpoi script in the .deb packages You should now be able to run overviewer.py --genpoi without error --- overviewer.py | 6 +++--- overviewer_core/aux_files/__init__.py | 0 genPOI.py => overviewer_core/aux_files/genPOI.py | 0 setup.py | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 overviewer_core/aux_files/__init__.py rename genPOI.py => overviewer_core/aux_files/genPOI.py (100%) diff --git a/overviewer.py b/overviewer.py index 55400ce..f714e62 100755 --- a/overviewer.py +++ b/overviewer.py @@ -106,9 +106,9 @@ def main(): if options.genpoi: # remove the "--genpoi" option from sys.argv before running genPI sys.argv.remove("--genpoi") - sys.path.append(".") - g = __import__("genPOI", {}, {}) - g.main() + #sys.path.append(".") + g = __import__("overviewer_core.aux_files", {}, {}, ["genPOI"]) + g.genPOI.main() return 0 if options.help: parser.print_help() diff --git a/overviewer_core/aux_files/__init__.py b/overviewer_core/aux_files/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/genPOI.py b/overviewer_core/aux_files/genPOI.py similarity index 100% rename from genPOI.py rename to overviewer_core/aux_files/genPOI.py diff --git a/setup.py b/setup.py index 583358c..2e20f66 100755 --- a/setup.py +++ b/setup.py @@ -108,7 +108,6 @@ if py2exe is not None: setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/web_assets', 'web_assets') setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/js_src', 'js_src') setup_kwargs['data_files'] += recursive_data_files('contrib', 'contrib') - setup_kwargs['data_files'] += [('', ['genPOI.py'])] setup_kwargs['zipfile'] = None if platform.system() == 'Windows' and '64bit' in platform.architecture(): b = 3 @@ -129,7 +128,7 @@ if py2app is not None: # script, package, and data # -setup_kwargs['packages'] = ['overviewer_core'] +setup_kwargs['packages'] = ['overviewer_core', 'overviewer_core/aux_files'] setup_kwargs['scripts'] = ['overviewer.py'] setup_kwargs['package_data'] = {'overviewer_core': recursive_package_data('data/textures') + recursive_package_data('data/web_assets') + recursive_package_data('data/js_src')} From d7b3054c421a657c2c0ca76acdfbaf4613452f26 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Thu, 3 May 2012 00:03:08 -0400 Subject: [PATCH 52/85] Allow zero as a valid rerenderprob --- overviewer_core/settingsValidators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index f7745d2..734f271 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -113,7 +113,7 @@ def validateNorthDirection(direction): def validateRerenderprob(s): val = float(s) - if val <= 0 or val >= 1: + if val < 0 or val >= 1: raise ValidationException("%r is not a valid rerender probability value. Should be between 0.0 and 1.0." % s) return val From eeb09f3d45ac8749d68a2b302dab38fb9b8ae216 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Thu, 3 May 2012 18:41:09 -0300 Subject: [PATCH 53/85] Fixed preform->perform typo THANKS m_pan! --- docs/design/designdoc.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/design/designdoc.rst b/docs/design/designdoc.rst index f319e2e..a69a099 100644 --- a/docs/design/designdoc.rst +++ b/docs/design/designdoc.rst @@ -17,7 +17,7 @@ So let's get started! .. note:: - This page is still under construction + This page is continually under construction .. contents:: @@ -82,7 +82,7 @@ pre-rendered sprite (a small image). The basic idea is to iterate over the blocks of the world and draw these sprites to the appropriate location on the map. -These are the high-level tasks The Overviewer must preform in rendering a map: +These are the high-level tasks The Overviewer must perform in rendering a map: 1. Render each block sprite from the textures 2. Scan the chunks of the world and determine which tiles need rendering @@ -143,7 +143,7 @@ transformations can be chained together simply by multiplying the transformation matrices together, only one transformation is actually done. This can be seen in the function -:func:`overviewer_core.textures.transform_image`. It preforms three steps: +:func:`overviewer_core.textures.transform_image`. It performs three steps: 1. The texture is re-sized to 17 by 17 pixels. This is done because the diagonal of a square with sides 17 is approximately 24, which is the target size for From f185fd9ec1ad016ac8156be21eedb7bb662e6f00 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 6 May 2012 12:54:40 -0400 Subject: [PATCH 54/85] Fix overlay issue where the overlay drop-down list would be empty --- overviewer_core/data/js_src/views.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 3ca20c4..884ac4e 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -31,6 +31,7 @@ overviewer.views.WorldView = Backbone.View.extend({ newMapType.shortname = tset.get("name"); newMapType.alt = "Minecraft " + tset.get("name") + " Map"; newMapType.projection = new overviewer.classes.MapProjection(); + newMapType._ov_tileSet = tset; if (tset.get("isOverlay")) { newMapType.tiles = tset.get("tilesets"); @@ -215,7 +216,7 @@ overviewer.views.GoogleMapView = Backbone.View.extend({ var gmapCurrent = overviewer.map.getMapTypeId(); for (id in currentWorldView.options.mapTypeIds) { if (currentWorldView.options.mapTypeIds[id] == gmapCurrent) { - this.options.currentTileSet = currentWorldView.model.get("tileSets").at(id); + this.options.currentTileSet = currentWorldView.options.mapTypes[id]._ov_tileSet; } } From 06b6af5dbcd8ac28af5feecdc282a8f5ee8be18a Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 6 May 2012 19:56:11 -0400 Subject: [PATCH 55/85] Fix texturepath docs (minor) --- docs/config.rst | 5 +++-- docs/running.rst | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index aa6965b..4436092 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -432,11 +432,12 @@ values. The valid configuration keys are listed below. **Default:** ``#1a1a1a`` -.. _option_texture_pack: +.. _option_texturepath: ``texturepath`` This is a where a specific texture pack can be found to be used during this render. - It can be either a folder or a directory. Its value should be a string. + It can be either a folder or a zip file containing the texture pack. + Its value should be a string. .. _crop: diff --git a/docs/running.rst b/docs/running.rst index 4d5fc42..2e5cb78 100644 --- a/docs/running.rst +++ b/docs/running.rst @@ -246,7 +246,7 @@ If you want or need to provide your own textures, you have several options: overviewer.exe. * Specify any terrain.png or texture pack you want with the - :ref:`texture_pack` option. + :ref:`texturepath` option. If you copy your world before you render it ------------------------------------------- From 34e5ddf620b18709ee401edc83ac3d4dd88a43da Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Sun, 6 May 2012 20:19:38 -0400 Subject: [PATCH 56/85] biomes are now murky *and* smooth closes issue #708 Props to mkor for taking advantage of the existing average loop, and CounterPillow for sussing out the correct biome multiplication color. This commit is just a teensy bit more future-proof. --- overviewer_core/src/composite.c | 5 -- overviewer_core/src/overviewer.h | 7 ++- overviewer_core/src/primitives/base.c | 79 +++++++++++++++------------ 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/overviewer_core/src/composite.c b/overviewer_core/src/composite.c index 2fc1c73..3267740 100644 --- a/overviewer_core/src/composite.c +++ b/overviewer_core/src/composite.c @@ -24,11 +24,6 @@ #include "overviewer.h" -/* like (a * b + 127) / 255), but much faster on most platforms - from PIL's _imaging.c */ -#define MULDIV255(a, b, tmp) \ - (tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8)) - typedef struct { PyObject_HEAD Imaging image; diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index c9b7ae6..f9091fa 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,13 +26,18 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 31 +#define OVERVIEWER_EXTENSION_VERSION 32 /* Python PIL, and numpy headers */ #include #include #include +/* like (a * b + 127) / 255), but much faster on most platforms + from PIL's _imaging.c */ +#define MULDIV255(a, b, tmp) \ + (tmp = (a) * (b) + 128, ((((tmp) >> 8) + (tmp)) >> 8)) + /* macro for getting a value out of various numpy arrays the 3D arrays have interesting, swizzled coordinates because minecraft (anvil) stores blocks in y/z/x order for 3D, z/x order for 2D */ diff --git a/overviewer_core/src/primitives/base.c b/overviewer_core/src/primitives/base.c index ae93db7..d23c098 100644 --- a/overviewer_core/src/primitives/base.c +++ b/overviewer_core/src/primitives/base.c @@ -29,46 +29,53 @@ typedef struct { typedef struct { const char* name; + float temperature; float rainfall; + + unsigned int r, g, b; } Biome; /* each entry in this table is yanked *directly* out of the minecraft source * temp/rainfall are taken from what MCP calls setTemperatureRainfall * + * Some biomes, like Swamp, do a bit of post-processing by multiplying on a + * hard-coded color. The RGB tuple used follows the temp/rainfall. + * 255, 255, 255 is white, which means do nothing + * * keep in mind the x/y coordinate in the color tables is found *after* * multiplying rainfall and temperature for the second coordinate, *and* the * origin is in the lower-right. <3 biomes. */ static Biome biome_table[] = { /* 0 */ - {"Ocean", 0.5, 0.5}, - {"Plains", 0.8, 0.4}, - {"Desert", 2.0, 0.0}, - {"Extreme Hills", 0.2, 0.3}, - {"Forest", 0.7, 0.8}, + {"Ocean", 0.5, 0.5, 255, 255}, + {"Plains", 0.8, 0.4, 255, 255, 255}, + {"Desert", 2.0, 0.0, 255, 255, 255}, + {"Extreme Hills", 0.2, 0.3, 255, 255, 255}, + {"Forest", 0.7, 0.8, 255, 255, 255}, /* 5 */ - {"Taiga", 0.05, 0.8}, - {"Swampland", 0.8, 0.9}, - {"River", 0.5, 0.5}, - {"Hell", 2.0, 0.0}, - {"Sky", 0.5, 0.5}, + {"Taiga", 0.05, 0.8, 255, 255, 255}, + {"Swampland", 0.8, 0.9, 205, 128, 255}, + {"River", 0.5, 0.5, 255, 255, 255}, + {"Hell", 2.0, 0.0, 255, 255, 255}, + {"Sky", 0.5, 0.5, 255, 255, 255}, /* 10 */ - {"FrozenOcean", 0.0, 0.5}, - {"FrozenRiver", 0.0, 0.5}, - {"Ice Plains", 0.0, 0.5}, - {"Ice Mountains", 0.0, 0.5}, - {"MushroomIsland", 0.9, 1.0}, + {"FrozenOcean", 0.0, 0.5, 255, 255, 255}, + {"FrozenRiver", 0.0, 0.5, 255, 255, 255}, + {"Ice Plains", 0.0, 0.5, 255, 255, 255}, + {"Ice Mountains", 0.0, 0.5, 255, 255, 255}, + {"MushroomIsland", 0.9, 1.0, 255, 255, 255}, /* 15 */ - {"MushroomIslandShore", 0.9, 1.0}, - {"Beach", 0.8, 0.4}, - {"DesertHills", 2.0, 0.0}, - {"ForestHills", 0.7, 0.8}, - {"TaigaHills", 0.05, 0.8}, + {"MushroomIslandShore", 0.9, 1.0, 255, 255, 255}, + {"Beach", 0.8, 0.4, 255, 255, 255}, + {"DesertHills", 2.0, 0.0, 255, 255, 255}, + {"ForestHills", 0.7, 0.8, 255, 255, 255}, + {"TaigaHills", 0.05, 0.8, 255, 255, 255}, /* 20 */ - {"Extreme Hills Edge", 0.2, 0.3}, - {"Jungle", 2.0, 0.45}, /* <-- GUESS, but a good one */ - {"Jungle Mountains", 2.0, 0.45}, /* <-- also a guess */ + {"Extreme Hills Edge", 0.2, 0.3, 255, 255, 255}, + {"Jungle", 2.0, 0.45, 255, 255, 255}, /* <-- GUESS, but a good one */ + {"Jungle Mountains", 2.0, 0.45, 255, 255, 255}, /* <-- also a guess */ }; #define NUM_BIOMES (sizeof(biome_table) / sizeof(Biome)) @@ -210,6 +217,8 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec int dx, dz; unsigned char tablex, tabley; float temp = 0.0, rain = 0.0; + unsigned int multr = 0, multg = 0, multb = 0; + int tmp; PyObject *color = NULL; if (self->use_biomes) { @@ -226,10 +235,17 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec temp += biome_table[biome].temperature; rain += biome_table[biome].rainfall; + multr += biome_table[biome].r; + multg += biome_table[biome].g; + multb += biome_table[biome].b; } } + temp /= 9.0; rain /= 9.0; + multr /= 9; + multg /= 9; + multb /= 9; } else { /* don't use biomes, just use the default */ temp = biome_table[DEFAULT_BIOME].temperature; @@ -258,19 +274,12 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)); g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)); b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)); - - /* swamp hack - All values are guessed. They are probably somewhat odd or - completely wrong, but this looks okay for me, and I'm male, - so I can only distinct about 10 different colors anyways. - Blame my Y-Chromosone. */ - if(biome == 6) { - r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)) * 0.8; - g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)) / 2.0; - b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)) * 1.0; - } - Py_DECREF(color); + + /* do the after-coloration */ + r = MULDIV255(r, multr, tmp); + g = MULDIV255(g, multg, tmp); + b = MULDIV255(b, multb, tmp); } /* final coloration */ From a456c2ae8a702925a46ff5721d1b1c403254b296 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 9 May 2012 20:47:49 -0400 Subject: [PATCH 57/85] Fixed bug in find_true_spawn when spawnY is at a chunk border Thanks to subz for pushing me to fix this! --- overviewer_core/world.py | 1 + 1 file changed, 1 insertion(+) diff --git a/overviewer_core/world.py b/overviewer_core/world.py index de6fd39..5d9de96 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -204,6 +204,7 @@ class World(object): if section['Y'] == targetSection: blockArray = section['Blocks'] return blockArray[inChunkX, inChunkZ, y % 16] + return 0 From 0245c91e6defced6665067058c687a3a11f0d07b Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 9 May 2012 21:26:05 -0400 Subject: [PATCH 58/85] Fix genpoi on windows --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2e20f66..5acc9bc 100755 --- a/setup.py +++ b/setup.py @@ -113,7 +113,8 @@ if py2exe is not None: b = 3 else: b = 1 - setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter', 'includes':['fileinput', 'overviewer_core.items']} + setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter', 'includes': + ['fileinput', 'overviewer_core.items', 'overviewer_core.aux_files.genPOI']} # # py2app options From 94c1e2980a39ffed22512f37fe63f1fdd85f5cf4 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Fri, 11 May 2012 22:09:10 -0300 Subject: [PATCH 59/85] Fixed ocean biomes being needlessly dark partial fix for issue #676; thanks @contre --- overviewer_core/src/primitives/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/src/primitives/base.c b/overviewer_core/src/primitives/base.c index d23c098..6ab8380 100644 --- a/overviewer_core/src/primitives/base.c +++ b/overviewer_core/src/primitives/base.c @@ -49,7 +49,7 @@ typedef struct { */ static Biome biome_table[] = { /* 0 */ - {"Ocean", 0.5, 0.5, 255, 255}, + {"Ocean", 0.5, 0.5, 255, 255, 255}, {"Plains", 0.8, 0.4, 255, 255, 255}, {"Desert", 2.0, 0.0, 255, 255, 255}, {"Extreme Hills", 0.2, 0.3, 255, 255, 255}, From fdda8234ff6170ab12a1e3aedc4ddb1e4fbfa700 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 11 May 2012 22:19:15 -0400 Subject: [PATCH 60/85] added warning for extremely absurd region files --- overviewer_core/tileset.py | 1 - overviewer_core/world.py | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index 9ee2305..07951f9 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -587,7 +587,6 @@ class TileSet(object): self.xradius = xradius self.yradius = yradius - def _rearrange_tiles(self): """If the target size of the tree is not the same as the existing size on disk, do some re-arranging diff --git a/overviewer_core/world.py b/overviewer_core/world.py index 5d9de96..c25a770 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -484,6 +484,8 @@ class RegionSet(object): p = f.split(".") x = int(p[1]) y = int(p[2]) + if x > 10000 or y > 10000: + logging.warning("Holy shit what is up with region file %s !?" % f) yield (x, y, path) class RegionSetWrapper(object): From 6009461239aa36d42955876e3c92b83d73cbe706 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 11 May 2012 22:23:42 -0400 Subject: [PATCH 61/85] fixed last commit to use absolute value and more reasonable threshold \o/ for padding my commit numbers! --- overviewer_core/world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/world.py b/overviewer_core/world.py index c25a770..279fa72 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -484,7 +484,7 @@ class RegionSet(object): p = f.split(".") x = int(p[1]) y = int(p[2]) - if x > 10000 or y > 10000: + if abs(x) > 500000 or abs(y) > 500000: logging.warning("Holy shit what is up with region file %s !?" % f) yield (x, y, path) From 792fcbbc0d4bf8c353f4554a8d44a993e6ddb453 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Mon, 14 May 2012 10:03:05 -0400 Subject: [PATCH 62/85] Provide better validation error message for markers Helps clarify #734 --- overviewer_core/settingsValidators.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index 734f271..41852f6 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -47,6 +47,8 @@ def validateMarkers(filterlist): if type(filterlist) != list: raise ValidationException("Markers must specify a list of filters. This has recently changed, so check the docs.") for x in filterlist: + if type(x) != dict: + raise ValidationException("Markers must specify a list of dictionaries. This has recently changed, so check the docs.") if "name" not in x: raise ValidationException("Must define a name") if "filterFunction" not in x: From 19cdca39d8be390aebfb548ab2591aa38b2b34a6 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 14 May 2012 22:35:00 -0300 Subject: [PATCH 63/85] Fixed world name for config example --- docs/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.rst b/docs/config.rst index 4436092..4011bb8 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -70,7 +70,7 @@ A more complicated example renders["survivalnight"] = { "world": "survival", - "title": "Survival Daytime", + "title": "Survival Nighttime", "rendermode": smooth_night, "dimension": "overworld", } From b53b20a9a8b6bc54547b89a4e60c70060f336c28 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Wed, 16 May 2012 10:01:27 +0200 Subject: [PATCH 64/85] Add the pre-1.3 wooden slabs. --- overviewer_core/src/primitives/edge-lines.c | 2 +- overviewer_core/textures.py | 51 +++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/overviewer_core/src/primitives/edge-lines.c b/overviewer_core/src/primitives/edge-lines.c index 00f12ae..6114309 100644 --- a/overviewer_core/src/primitives/edge-lines.c +++ b/overviewer_core/src/primitives/edge-lines.c @@ -41,7 +41,7 @@ edge_lines_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, P int x = state->x, y = state->y, z = state->z; int increment=0; - if (state->block == 44 && ((state->block_data & 0x8) == 0 )) // half-step BUT no upsidown half-step + if ((state->block == 44 || state->block == 126) && ((state->block_data & 0x8) == 0 )) // half-steps BUT no upsidown half-steps increment=6; else if ((state->block == 78) || (state->block == 93) || (state->block == 94)) // snow, redstone repeaters (on and off) increment=9; diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index ca891de..3b305c1 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -1336,6 +1336,8 @@ block(blockid=41, top_index=23) block(blockid=42, top_index=22) # double slabs and slabs +# these wooden slabs are unobtainable without cheating, they are still +# here because lots of pre-1.3 worlds use this blocks @material(blockid=[43, 44], data=range(16), transparent=(44,), solid=True) def slabs(self, blockid, data): texture = data & 7 @@ -3169,3 +3171,52 @@ block(blockid=123, top_index=211) # active redstone lamp block(blockid=124, top_index=212) + +# wooden double and normal slabs +# these are the new wooden slabs, blockids 43 44 still have wooden +# slabs, but those are unobtainable without cheating +@material(blockid=[125, 126], data=range(16), transparent=(44,), solid=True) +def slabs(self, blockid, data): + texture = data & 7 + if texture== 0: # oak + top = side = self.terrain_images[4] + elif texture== 1: # spruce + top = side = self.terrain_images[198] + elif texture== 2: # birch + top = side = self.terrain_images[214] + elif texture== 3: # jungle + top = side = self.terrain_images[199] + else: + return None + + if blockid == 125: # double slab + return self.build_block(top, side) + + # cut the side texture in half + mask = side.crop((0,8,16,16)) + side = Image.new(side.mode, side.size, self.bgcolor) + alpha_over(side, mask,(0,0,16,8), mask) + + # plain slab + top = self.transform_image_top(top) + side = self.transform_image_side(side) + otherside = side.transpose(Image.FLIP_LEFT_RIGHT) + + sidealpha = side.split()[3] + side = ImageEnhance.Brightness(side).enhance(0.9) + side.putalpha(sidealpha) + othersidealpha = otherside.split()[3] + otherside = ImageEnhance.Brightness(otherside).enhance(0.8) + otherside.putalpha(othersidealpha) + + # upside down slab + delta = 0 + if data & 8 == 8: + delta = 6 + + img = Image.new("RGBA", (24,24), self.bgcolor) + alpha_over(img, side, (0,12 - delta), side) + alpha_over(img, otherside, (12,12 - delta), otherside) + alpha_over(img, top, (0,6 - delta), top) + + return img From f395a13d98b6d40a170a3e590a5c7ad9f0ede90a Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Wed, 16 May 2012 10:15:38 -0400 Subject: [PATCH 65/85] biomes=False now renders correctly again Closes Issue #737 --- overviewer_core/src/overviewer.h | 2 +- overviewer_core/src/primitives/base.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index f9091fa..563c19b 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 32 +#define OVERVIEWER_EXTENSION_VERSION 33 /* Python PIL, and numpy headers */ #include diff --git a/overviewer_core/src/primitives/base.c b/overviewer_core/src/primitives/base.c index 6ab8380..64f0443 100644 --- a/overviewer_core/src/primitives/base.c +++ b/overviewer_core/src/primitives/base.c @@ -250,6 +250,9 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec /* don't use biomes, just use the default */ temp = biome_table[DEFAULT_BIOME].temperature; rain = biome_table[DEFAULT_BIOME].rainfall; + multr = biome_table[DEFAULT_BIOME].r; + multg = biome_table[DEFAULT_BIOME].g; + multb = biome_table[DEFAULT_BIOME].b; } /* second coordinate is actually scaled to fit inside the triangle From 75f80dae954c565cb62089b10cc7c075f4bf1ea1 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 17 May 2012 10:25:03 +0200 Subject: [PATCH 66/85] Fix black dotted lines in smooth-lighting rendermode. --- overviewer_core/src/primitives/smooth-lighting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/src/primitives/smooth-lighting.c b/overviewer_core/src/primitives/smooth-lighting.c index 6e3da54..8840253 100644 --- a/overviewer_core/src/primitives/smooth-lighting.c +++ b/overviewer_core/src/primitives/smooth-lighting.c @@ -143,7 +143,7 @@ do_shading_with_rule(RenderPrimitiveSmoothLighting *self, RenderState *state, st int cz = state->z + face.dz; /* first, check for occlusion if the block is in the local chunk */ - if (lighting_is_face_occluded(state, 0, cx, cy, cz)) + if (lighting_is_face_occluded(state, 1, cx, cy, cz)) return; /* calculate the lighting colors for each point */ From fc84f8c892448f85746453c002edea5d25a2237c Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Sat, 19 May 2012 17:13:49 -0300 Subject: [PATCH 67/85] Edited error message for missing texture file(s) Now links to the docs for more information. --- overviewer_core/textures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index ca891de..b19eb9f 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -213,7 +213,7 @@ class Textures(object): if verbose: logging.info("Found %s in '%s'", filename, path) return open(path, mode) - raise IOError("Could not find the file `{0}'. Try specifying the 'texturepath' option in your config file. Set it to the directory where I can find {0}.".format(filename)) + raise IOError("Could not find the file `{0}'. Try specifying the 'texturepath' option in your config file. Set it to the directory where I can find {0}. Also see ".format(filename)) def load_image(self, filename): """Returns an image object""" From ab04603ef81f125be4b0ed5c28bdd2f92944edd5 Mon Sep 17 00:00:00 2001 From: mc-zem Date: Mon, 21 May 2012 18:30:02 +0200 Subject: [PATCH 68/85] added nowrap to sign dropdown label style --- overviewer_core/data/js_src/views.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 884ac4e..0d185ed 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -488,13 +488,13 @@ overviewer.views.SignControlView = Backbone.View.extend({ var textNode = document.createElement('text'); if(item.icon) { textNode.innerHTML = '' + item.label + '
'; + item.icon + '">' + item.label + ' 
'; } else { - textNode.innerHTML = item.label + '
'; + textNode.innerHTML = item.label + ' 
'; } itemDiv.appendChild(textNode); - + itemDiv.style.whiteSpace = "nowrap"; }, }); From 98121dd9602d97b263a2763409e0f64821fc5dc1 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 25 May 2012 15:31:27 -0400 Subject: [PATCH 69/85] validated paths are run through os.path.expandvars() Now one can use vars in config file paths, which eases the transition from command line setups to config file setups. --- overviewer_core/settingsValidators.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index 41852f6..58e4835 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -17,6 +17,12 @@ class Setting(object): self.validator = validator self.default = default +def expand_path(p): + p = os.path.expanduser(p) + p = os.path.expandvars(p) + p = os.path.abspath(p) + return p + def checkBadEscape(s): fixed = False fixed_string = s @@ -67,7 +73,7 @@ def validateOverlays(renderlist): def validateWorldPath(worldpath): _, worldpath = checkBadEscape(worldpath) - abs_path = os.path.abspath(os.path.expanduser(worldpath)) + abs_path = expand_path(worldpath) if not os.path.exists(os.path.join(abs_path, "level.dat")): raise ValidationException("No level.dat file in '%s'. Are you sure you have the right path?" % (abs_path,)) return abs_path @@ -158,7 +164,7 @@ def validateOptImg(opt): def validateTexturePath(path): # Expand user dir in directories strings - path = os.path.expanduser(path) + path = expand_path(path) # TODO assert this path exists? return path @@ -184,7 +190,7 @@ def validateOutputDir(d): _, d = checkBadEscape(d) if not d.strip(): raise ValidationException("You must specify a valid output directory") - return os.path.abspath(d) + return expand_path(d) def validateCrop(value): if len(value) != 4: From f0d48347a47c7ac2e2198b0a07d3c13db01d7082 Mon Sep 17 00:00:00 2001 From: Socolin Date: Tue, 22 May 2012 10:55:27 +0300 Subject: [PATCH 70/85] Fix new map format, to support the 4096 ids --- overviewer_core/world.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/overviewer_core/world.py b/overviewer_core/world.py index 279fa72..bce578a 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -305,7 +305,7 @@ class RegionSet(object): * For each chunk section: * The "Blocks" byte string is transformed into a 16x16x16 numpy array - * The AddBlocks array, if it exists, is bitshifted left 8 bits and + * The Add array, if it exists, is bitshifted left 8 bits and added into the Blocks array * The "SkyLight" byte string is transformed into a 16x16x128 numpy array @@ -381,11 +381,11 @@ class RegionSet(object): # Cast up to uint16, blocks can have up to 12 bits of data blocks = blocks.astype(numpy.uint16) blocks = blocks.reshape((16,16,16)) - if "AddBlocks" in section: + if "Add" in section: # This section has additional bits to tack on to the blocks - # array. AddBlocks is a packed array with 4 bits per slot, so + # array. Add is a packed array with 4 bits per slot, so # it needs expanding - additional = numpy.frombuffer(section['AddBlocks'], dtype=numpy.uint8) + additional = numpy.frombuffer(section['Add'], dtype=numpy.uint8) additional = additional.astype(numpy.uint16).reshape((16,16,8)) additional_expanded = numpy.empty((16,16,16), dtype=numpy.uint16) additional_expanded[:,:,::2] = (additional & 0x0F) << 8 @@ -393,7 +393,7 @@ class RegionSet(object): blocks += additional_expanded del additional del additional_expanded - del section['AddBlocks'] # Save some memory + del section['Add'] # Save some memory section['Blocks'] = blocks # Turn the skylight array into a 16x16x16 matrix. The array comes From b245bbe8b302d3453bbcb73fc6d41a0a73db9b8a Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 31 May 2012 12:04:58 +0200 Subject: [PATCH 71/85] Update chests to work with snapshot 12w21b. Add ender chests. Improve some comments. --- overviewer_core/src/iterate.c | 67 ++++------ overviewer_core/textures.py | 227 ++++++++++++++++++++++++++++------ 2 files changed, 207 insertions(+), 87 deletions(-) diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index bbc9446..f4f9a48 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -321,71 +321,46 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { } return final_data; - } else if (state-> block == 54) { /* chests */ - /* the top 2 bits are used to store the type of chest - * (single or double), the 2 bottom bits are used for - * orientation, look textures.py for more information. */ + } else if (state->block == 54) { /* normal chests */ + /* Orientation is given by ancilData, pseudo data needed to + * choose from single or double chest and the correct half of + * the chest. */ + + /* Add two bits to ancilData to store single or double chest + * and which half of the chest it is: bit 0x10 = second half + * bit 0x8 = first half */ - /* if placed alone chests always face west, return 0 to make a - * chest facing west */ - unsigned char chest_data = 0, air_data = 0, final_data = 0; + unsigned char chest_data = 0, final_data = 0; /* search for chests */ chest_data = check_adjacent_blocks(state, x, y, z, 54); - /* search for air */ - air_data = check_adjacent_blocks(state, x, y, z, 0); + if (chest_data == 1) { /* another chest in the upper-left */ + final_data = final_data | 0x10 | ancilData; - if (chest_data == 1) { /* another chest in the east */ - final_data = final_data | 0x8; /* only can face to north or south */ - if ( (air_data & 0x2) == 2 ) { - final_data = final_data | 0x1; /* facing north */ - } else { - final_data = final_data | 0x3; /* facing south */ - } + } else if (chest_data == 2) { /* in the bottom-left */ + final_data = final_data | 0x8 | ancilData; - } else if (chest_data == 2) { /* in the north */ - final_data = final_data | 0x4; /* only can face to east or west */ - if ( !((air_data & 0x4) == 4) ) { /* 0 = west */ - final_data = final_data | 0x2; /* facing east */ - } + } else if (chest_data == 4) { /*in the bottom-right */ + final_data = final_data | 0x8 | ancilData; - } else if (chest_data == 4) { /*in the west */ - final_data = final_data | 0x4; - if ( (air_data & 0x2) == 2 ) { - final_data = final_data | 0x1; /* facing north */ - } else { - final_data = final_data | 0x3; /* facing south */ - } - - } else if (chest_data == 8) { /*in the south */ - final_data = final_data | 0x8; - if ( !((air_data & 0x4) == 4) ) { - final_data = final_data | 0x2; /* facing east */ - } + } else if (chest_data == 8) { /*in the upper-right */ + final_data = final_data | 0x10 | ancilData; } else if (chest_data == 0) { /* Single chest, determine the orientation */ - if ( ((air_data & 0x8) == 0) && ((air_data & 0x2) == 2) ) { /* block in +x and no block in -x */ - final_data = final_data | 0x1; /* facing north */ - - } else if ( ((air_data & 0x2) == 0) && ((air_data & 0x8) == 8)) { - final_data = final_data | 0x3; - - } else if ( ((air_data & 0x4) == 0) && ((air_data & 0x1) == 1)) { - final_data = final_data | 0x2; - } /* else, facing west, value = 0 */ + final_data = ancilData; } else { - /* more than one adjacent chests! render as normal chest */ + /* more than one adjacent chests! That shouldn't be + * possible! render as normal chest */ return 0; } - return final_data; } else if ((state->block == 101) || (state->block == 102)) { /* iron bars and glass panes: - * they seem to stick to almost everything but air, but + * they seem to stick to almost everything but air, * not sure yet! Still a TODO! */ /* return check adjacent blocks with air, bit inverted */ return check_adjacent_blocks(state, x, y, z, 0) ^ 0x0f; diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 3b305c1..3c20f94 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -131,7 +131,7 @@ class Textures(object): # a list of subdirectories to search for a given file, # after the obvious '.' - search_dirs = ['anim', 'misc', 'environment'] + search_dirs = ['anim', 'misc', 'environment', 'item'] search_zip_paths = [filename,] + [d + '/' + filename for d in search_dirs] def search_dir(base): """Search the given base dir for filename, in search_dirs.""" @@ -1610,50 +1610,195 @@ def stairs(self, blockid, data): return img -# normal and locked chest (locked was the one used in april fools' day) -# uses pseudo-ancildata found in iterate.c -@material(blockid=[54,95], data=range(12), solid=True) +# normal, locked (used in april's fool day) and ender chests chests +@material(blockid=[54,95,130], data=range(30), transparent = True) def chests(self, blockid, data): - # First two bits of the pseudo data store if it's a single chest - # or it's a double chest, first half or second half (left to right). - # The last two bits store the orientation. + # the first 3 bits are the orientation as stored in minecraft, + # bits 0x8 and 0x10 indicate which half of the double chest is it. - # No need for rotation stuff, uses pseudo data and rotates with the map + # first, do the rotation if needed + orientation_data = data & 7 + if self.rotation == 1: + if orientation_data == 2: data = 5 | (data & 24) + elif orientation_data == 3: data = 4 | (data & 24) + elif orientation_data == 4: data = 2 | (data & 24) + elif orientation_data == 5: data = 3 | (data & 24) + elif self.rotation == 2: + if orientation_data == 2: data = 3 | (data & 24) + elif orientation_data == 3: data = 2 | (data & 24) + elif orientation_data == 4: data = 5 | (data & 24) + elif orientation_data == 5: data = 4 | (data & 24) + elif self.rotation == 3: + if orientation_data == 2: data = 4 | (data & 24) + elif orientation_data == 3: data = 5 | (data & 24) + elif orientation_data == 4: data = 3 | (data & 24) + elif orientation_data == 5: data = 2 | (data & 24) + + if blockid in (95,130) and not data in [2,3,4,5]: return None + # iterate.c will only return the ancil data (without pseudo + # ancil data) for locked and ender chests, so only + # ancilData = 2,3,4,5 are used for this blockids + + if data & 24 == 0: + if blockid == 130: t = self.load_image("enderchest.png") + else: t = self.load_image("chest.png") + t.save("textura.png") + # the textures is no longer in terrain.png, get it from + # item/chest.png and get by cropping all the needed stuff + if t.size != (64,64): t = t.resize((64,64), Image.ANTIALIAS) + # top + top = t.crop((14,0,28,14)) + top.load() # every crop need a load, crop is a lazy operation + # see PIL manual + img = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(img,top,(1,1)) + top = img + # front + front_top = t.crop((14,14,28,19)) + front_top.load() + front_bottom = t.crop((14,34,28,43)) + front_bottom.load() + front_lock = t.crop((1,0,3,4)) + front_lock.load() + front = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(front,front_top, (1,1)) + alpha_over(front,front_bottom, (1,6)) + alpha_over(front,front_lock, (7,3)) + # left side + # left side, right side, and back are esentially the same for + # the default texture, we take it anyway just in case other + # textures make use of it. + side_l_top = t.crop((0,14,14,19)) + side_l_top.load() + side_l_bottom = t.crop((0,34,14,43)) + side_l_bottom.load() + side_l = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_l,side_l_top, (1,1)) + alpha_over(side_l,side_l_bottom, (1,6)) + # right side + side_r_top = t.crop((28,14,43,20)) + side_r_top.load() + side_r_bottom = t.crop((28,33,42,43)) + side_r_bottom.load() + side_r = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_r,side_l_top, (1,1)) + alpha_over(side_r,side_l_bottom, (1,6)) + # back + back_top = t.crop((42,14,56,18)) + back_top.load() + back_bottom = t.crop((42,33,56,43)) + back_bottom.load() + back = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(back,side_l_top, (1,1)) + alpha_over(back,side_l_bottom, (1,6)) - top = self.terrain_images[25] - side = self.terrain_images[26] - - if data & 12 == 0: # single chest - front = self.terrain_images[27] - back = self.terrain_images[26] - - elif data & 12 == 4: # double, first half - front = self.terrain_images[41] - back = self.terrain_images[57] - - elif data & 12 == 8: # double, second half - front = self.terrain_images[42] - back = self.terrain_images[58] - - else: # just in case - front = self.terrain_images[25] - side = self.terrain_images[25] - back = self.terrain_images[25] - - if data & 3 == 0: # facing west - img = self.build_full_block(top, None, None, side, front) - - elif data & 3 == 1: # north - img = self.build_full_block(top, None, None, front, side) - - elif data & 3 == 2: # east - img = self.build_full_block(top, None, None, side, back) - - elif data & 3 == 3: # south - img = self.build_full_block(top, None, None, back, side) - else: - img = self.build_full_block(top, None, None, back, side) + # large chest + # the textures is no longer in terrain.png, get it from + # item/chest.png and get all the needed stuff + t = self.load_image("largechest.png") + if t.size != (128,64): t = t.resize((128,64), Image.ANTIALIAS) + # top + top = t.crop((14,0,44,14)) + top.load() + img = Image.new("RGBA", (32,16), self.bgcolor) + alpha_over(img,top,(1,1)) + top = img + # front + front_top = t.crop((14,14,44,18)) + front_top.load() + front_bottom = t.crop((14,33,44,43)) + front_bottom.load() + front_lock = t.crop((1,0,3,5)) + front_lock.load() + front = Image.new("RGBA", (32,16), self.bgcolor) + alpha_over(front,front_top,(1,1)) + alpha_over(front,front_bottom,(1,5)) + alpha_over(front,front_lock,(15,3)) + # left side + side_l_top = t.crop((0,14,14,18)) + side_l_top.load() + side_l_bottom = t.crop((0,33,14,43)) + side_l_bottom.load() + side_l = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_l,side_l_top, (1,1)) + alpha_over(side_l,side_l_bottom,(1,5)) + # right side + side_r_top = t.crop((44,14,58,18)) + side_r_top.load() + side_r_bottom = t.crop((44,33,58,43)) + side_r_bottom.load() + side_r = Image.new("RGBA", (16,16), self.bgcolor) + alpha_over(side_r,side_r_top, (1,1)) + alpha_over(side_r,side_r_bottom,(1,5)) + # back + back_top = t.crop((58,14,88,18)) + back_top.load() + back_bottom = t.crop((58,33,88,43)) + back_bottom.load() + back = Image.new("RGBA", (32,16), self.bgcolor) + alpha_over(back,back_top,(1,1)) + alpha_over(back,back_bottom,(1,5)) + + + if data & 24 == 8: # double chest, first half + top = top.crop((0,0,16,16)) + top.load() + front = front.crop((0,0,16,16)) + front.load() + back = back.crop((0,0,16,16)) + back.load() + #~ side = side_l + + elif data & 24 == 16: # double, second half + top = top.crop((16,0,32,16)) + top.load() + front = front.crop((16,0,32,16)) + front.load() + back = back.crop((16,0,32,16)) + back.load() + #~ side = side_r + + else: # just in case + return None + + # compose the final block + img = Image.new("RGBA", (24,24), self.bgcolor) + if data & 7 == 2: # north + side = self.transform_image_side(side_r) + alpha_over(img, side, (1,7)) + back = self.transform_image_side(back) + alpha_over(img, back.transpose(Image.FLIP_LEFT_RIGHT), (11,7)) + front = self.transform_image_side(front) + top = self.transform_image_top(top.rotate(180)) + alpha_over(img, top, (0,2)) + + elif data & 7 == 3: # south + side = self.transform_image_side(side_l) + alpha_over(img, side, (1,7)) + front = self.transform_image_side(front).transpose(Image.FLIP_LEFT_RIGHT) + top = self.transform_image_top(top.rotate(180)) + alpha_over(img, top, (0,2)) + alpha_over(img, front,(11,7)) + + elif data & 7 == 4: # west + side = self.transform_image_side(side_r) + alpha_over(img, side.transpose(Image.FLIP_LEFT_RIGHT), (11,7)) + front = self.transform_image_side(front) + alpha_over(img, front,(1,7)) + top = self.transform_image_top(top.rotate(270)) + alpha_over(img, top, (0,2)) + + elif data & 7 == 5: # east + back = self.transform_image_side(back) + side = self.transform_image_side(side_l).transpose(Image.FLIP_LEFT_RIGHT) + alpha_over(img, side, (11,7)) + alpha_over(img, back, (1,7)) + top = self.transform_image_top(top.rotate(270)) + alpha_over(img, top, (0,2)) + + else: # just in case + img = None return img From 86ad4bf611cfe76d78c9efe2d43a6e06b1abd360 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Thu, 31 May 2012 13:43:53 +0200 Subject: [PATCH 72/85] Add emerald ore and sandstone stairs. --- overviewer_core/textures.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 3c20f94..9eeb6ae 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -1491,8 +1491,8 @@ def fire(self, blockid, data): # monster spawner block(blockid=52, top_index=34, transparent=True) -# wooden, cobblestone, red brick, stone brick and netherbrick stairs. -@material(blockid=[53,67,108,109,114], data=range(8), transparent=True, solid=True, nospawn=True) +# wooden, cobblestone, red brick, stone brick, netherbrick and sandstone stairs. +@material(blockid=[53,67,108,109,114,128], data=range(8), transparent=True, solid=True, nospawn=True) def stairs(self, blockid, data): # first, rotations @@ -1526,7 +1526,9 @@ def stairs(self, blockid, data): texture = self.terrain_images[54] elif blockid == 114: # netherbrick stairs texture = self.terrain_images[224] - + elif blockid ==128: #sandstone stairs + texture = self.terrain_images[192] + side = texture.copy() half_block_u = texture.copy() # up, down, left, right half_block_d = texture.copy() @@ -3365,3 +3367,6 @@ def slabs(self, blockid, data): alpha_over(img, top, (0,6 - delta), top) return img + +# emerald ore +block(blockid=130, top_index=171) From 85c439b68c4e58a84d289d0a8b225efd40504aa3 Mon Sep 17 00:00:00 2001 From: Alejandro Aguilera Date: Fri, 1 Jun 2012 14:14:40 +0200 Subject: [PATCH 73/85] Add emerald block, improve the looking of the brewing stand. --- overviewer_core/textures.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 9eeb6ae..7758e26 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -3232,8 +3232,11 @@ def enchantment_table(self, blockid, data): # TODO this is a place holder, is a 2d image pasted @material(blockid=117, data=range(5), transparent=True) def brewing_stand(self, blockid, data): + base = self.terrain_images[156] + img = self.build_full_block(None, None, None, None, None, base) t = self.terrain_images[157] - img = self.build_billboard(t) + stand = self.build_billboard(t) + alpha_over(img,stand,(0,-2)) return img # cauldron @@ -3370,3 +3373,6 @@ def slabs(self, blockid, data): # emerald ore block(blockid=130, top_index=171) + +# emerald block +block(blockid=133, top_index=25) From 4ae77a9f47a4c693f4e51545a07f400b9c605ba5 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 3 Jun 2012 21:19:39 -0400 Subject: [PATCH 74/85] Force rebuild due to new texture stuff --- overviewer_core/src/overviewer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index 563c19b..af15a4d 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 33 +#define OVERVIEWER_EXTENSION_VERSION 34 /* Python PIL, and numpy headers */ #include From e0a4976e6aaa13aa346ecdf76f9b81c46b82cc93 Mon Sep 17 00:00:00 2001 From: alexan Date: Sun, 6 May 2012 16:06:04 +0300 Subject: [PATCH 75/85] make create info window optional parameter --- docs/signs.rst | 5 ++++- overviewer_core/aux_files/genPOI.py | 14 +++++++++----- overviewer_core/data/js_src/views.js | 10 ++++++++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/docs/signs.rst b/docs/signs.rst index 415e581..d0487e2 100644 --- a/docs/signs.rst +++ b/docs/signs.rst @@ -93,7 +93,7 @@ of dictionaries. For example:: 'world': 'myworld', 'title': "Example", 'markers': [dict(name="All signs", filterFunction=signFilter), - dict(name="Chests", filterFunction=chestFilter, icon="chest.png")] + dict(name="Chests", filterFunction=chestFilter, icon="chest.png", createInfoWindow=False)] } @@ -112,6 +112,9 @@ The following keys are accepted in the marker dictionary: on the POI itself (this can be done by modifying the POI in the filter function. See the example above) +``createInfoWindow`` + Optional. Specifies wether or not the icon displays a spezial info window on click. Defaults to true + Generating the POI Markers ========================== diff --git a/overviewer_core/aux_files/genPOI.py b/overviewer_core/aux_files/genPOI.py index 9b80a60..f67e556 100755 --- a/overviewer_core/aux_files/genPOI.py +++ b/overviewer_core/aux_files/genPOI.py @@ -153,15 +153,15 @@ def main(): return 1 for f in render['markers']: - d = dict(icon="signpost_icon.png") + d = dict(icon="signpost_icon.png", createInfoWindow=True) d.update(f) markersets.add(((d['name'], d['filterFunction']), rset)) name = f['name'].replace(" ","_") + hex(hash(f['filterFunction']))[-4:] + "_" + hex(hash(rset))[-4:] try: l = markers[rname] - l.append(dict(groupName=name, displayName = f['name'], icon=d['icon'])) + l.append(dict(groupName=name, displayName = f['name'], icon=d['icon'], createInfoWindow=d['createInfoWindow'])) except KeyError: - markers[rname] = [dict(groupName=name, displayName=f['name'], icon=d['icon']),] + markers[rname] = [dict(groupName=name, displayName=f['name'], icon=d['icon'], createInfoWindow=d['createInfoWindow']),] handleSigns(rset, os.path.join(destdir, rname), render, rname) handlePlayers(rset, render, worldpath) @@ -179,16 +179,20 @@ def main(): for poi in rset._pois['TileEntities']: result = filter_function(poi) if result: - d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True) + d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result) if "icon" in poi: d.update({"icon": poi['icon']}) + if "createInfoWindow" in poi: + d.update({"createInfoWindow": poi['createInfoWindow']}) markerSetDict[name]['raw'].append(d) for poi in rset._pois['Players']: result = filter_function(poi) if result: - d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result, createInfoWindow=True) + d = dict(x=poi['x'], y=poi['y'], z=poi['z'], text=result) if "icon" in poi: d.update({"icon": poi['icon']}) + if "createInfoWindow" in poi: + d.update({"createInfoWindow": poi['createInfoWindow']}) markerSetDict[name]['raw'].append(d) #print markerSetDict diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 0d185ed..ae1a39e 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -458,8 +458,14 @@ overviewer.views.SignControlView = Backbone.View.extend({ 'icon': iconURL, 'visible': false }); - if (entity.createInfoWindow) { - overviewer.util.createMarkerInfoWindow(marker); + if(entity['createInfoWindow']) { + if (entity.createInfoWindow) { + overviewer.util.createMarkerInfoWindow(marker); + } + } else { + if(dataRoot[i].createInfoWindow) { + overviewer.util.createMarkerInfoWindow(marker); + } } jQuery.extend(entity, {markerObj: marker}); } From 7f1ccdc156488fdb7bcf5a1780374f1ef77efe77 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Sun, 3 Jun 2012 22:55:20 -0400 Subject: [PATCH 76/85] Fix up pull request #726 --- docs/signs.rst | 2 +- overviewer_core/data/js_src/views.js | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/signs.rst b/docs/signs.rst index d0487e2..8384694 100644 --- a/docs/signs.rst +++ b/docs/signs.rst @@ -113,7 +113,7 @@ The following keys are accepted in the marker dictionary: example above) ``createInfoWindow`` - Optional. Specifies wether or not the icon displays a spezial info window on click. Defaults to true + Optional. Specifies whether or not the icon displays an info window on click. Defaults to True Generating the POI Markers diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index ae1a39e..179d0b0 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -458,12 +458,10 @@ overviewer.views.SignControlView = Backbone.View.extend({ 'icon': iconURL, 'visible': false }); - if(entity['createInfoWindow']) { - if (entity.createInfoWindow) { - overviewer.util.createMarkerInfoWindow(marker); - } + if(entity['createInfoWindow'] == true) { + overviewer.util.createMarkerInfoWindow(marker); } else { - if(dataRoot[i].createInfoWindow) { + if(dataRoot[i].createInfoWindow == true) { overviewer.util.createMarkerInfoWindow(marker); } } From d329e34fe9a5f5ff57ea7a537c5ab92097c4b989 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 4 Jun 2012 21:57:37 -0400 Subject: [PATCH 77/85] Revert "Add emerald block, improve the looking of the brewing stand." This reverts commit 85c439b68c4e58a84d289d0a8b225efd40504aa3. --- overviewer_core/textures.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index bc1f498..0db885f 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -3232,11 +3232,8 @@ def enchantment_table(self, blockid, data): # TODO this is a place holder, is a 2d image pasted @material(blockid=117, data=range(5), transparent=True) def brewing_stand(self, blockid, data): - base = self.terrain_images[156] - img = self.build_full_block(None, None, None, None, None, base) t = self.terrain_images[157] - stand = self.build_billboard(t) - alpha_over(img,stand,(0,-2)) + img = self.build_billboard(t) return img # cauldron @@ -3373,6 +3370,3 @@ def slabs(self, blockid, data): # emerald ore block(blockid=130, top_index=171) - -# emerald block -block(blockid=133, top_index=25) From 365c67cf94b8461e40b984fd5bb3cedf337f7561 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 4 Jun 2012 21:57:41 -0400 Subject: [PATCH 78/85] Revert "Add emerald ore and sandstone stairs." This reverts commit 86ad4bf611cfe76d78c9efe2d43a6e06b1abd360. --- overviewer_core/textures.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index 0db885f..f388c49 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -1491,8 +1491,8 @@ def fire(self, blockid, data): # monster spawner block(blockid=52, top_index=34, transparent=True) -# wooden, cobblestone, red brick, stone brick, netherbrick and sandstone stairs. -@material(blockid=[53,67,108,109,114,128], data=range(8), transparent=True, solid=True, nospawn=True) +# wooden, cobblestone, red brick, stone brick and netherbrick stairs. +@material(blockid=[53,67,108,109,114], data=range(8), transparent=True, solid=True, nospawn=True) def stairs(self, blockid, data): # first, rotations @@ -1526,9 +1526,7 @@ def stairs(self, blockid, data): texture = self.terrain_images[54] elif blockid == 114: # netherbrick stairs texture = self.terrain_images[224] - elif blockid ==128: #sandstone stairs - texture = self.terrain_images[192] - + side = texture.copy() half_block_u = texture.copy() # up, down, left, right half_block_d = texture.copy() @@ -3367,6 +3365,3 @@ def slabs(self, blockid, data): alpha_over(img, top, (0,6 - delta), top) return img - -# emerald ore -block(blockid=130, top_index=171) From a60b56c507ba54121e77f3a7647a6a41dca25326 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 4 Jun 2012 21:57:42 -0400 Subject: [PATCH 79/85] Revert "Update chests to work with snapshot 12w21b. Add ender chests. Improve some comments." This reverts commit b245bbe8b302d3453bbcb73fc6d41a0a73db9b8a. --- overviewer_core/src/iterate.c | 67 +++++++---- overviewer_core/textures.py | 219 ++++++---------------------------- 2 files changed, 83 insertions(+), 203 deletions(-) diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index f4f9a48..bbc9446 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -321,46 +321,71 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { } return final_data; - } else if (state->block == 54) { /* normal chests */ - /* Orientation is given by ancilData, pseudo data needed to - * choose from single or double chest and the correct half of - * the chest. */ - - /* Add two bits to ancilData to store single or double chest - * and which half of the chest it is: bit 0x10 = second half - * bit 0x8 = first half */ + } else if (state-> block == 54) { /* chests */ + /* the top 2 bits are used to store the type of chest + * (single or double), the 2 bottom bits are used for + * orientation, look textures.py for more information. */ - unsigned char chest_data = 0, final_data = 0; + /* if placed alone chests always face west, return 0 to make a + * chest facing west */ + unsigned char chest_data = 0, air_data = 0, final_data = 0; /* search for chests */ chest_data = check_adjacent_blocks(state, x, y, z, 54); - if (chest_data == 1) { /* another chest in the upper-left */ - final_data = final_data | 0x10 | ancilData; + /* search for air */ + air_data = check_adjacent_blocks(state, x, y, z, 0); - } else if (chest_data == 2) { /* in the bottom-left */ - final_data = final_data | 0x8 | ancilData; + if (chest_data == 1) { /* another chest in the east */ + final_data = final_data | 0x8; /* only can face to north or south */ + if ( (air_data & 0x2) == 2 ) { + final_data = final_data | 0x1; /* facing north */ + } else { + final_data = final_data | 0x3; /* facing south */ + } - } else if (chest_data == 4) { /*in the bottom-right */ - final_data = final_data | 0x8 | ancilData; + } else if (chest_data == 2) { /* in the north */ + final_data = final_data | 0x4; /* only can face to east or west */ + if ( !((air_data & 0x4) == 4) ) { /* 0 = west */ + final_data = final_data | 0x2; /* facing east */ + } - } else if (chest_data == 8) { /*in the upper-right */ - final_data = final_data | 0x10 | ancilData; + } else if (chest_data == 4) { /*in the west */ + final_data = final_data | 0x4; + if ( (air_data & 0x2) == 2 ) { + final_data = final_data | 0x1; /* facing north */ + } else { + final_data = final_data | 0x3; /* facing south */ + } + + } else if (chest_data == 8) { /*in the south */ + final_data = final_data | 0x8; + if ( !((air_data & 0x4) == 4) ) { + final_data = final_data | 0x2; /* facing east */ + } } else if (chest_data == 0) { /* Single chest, determine the orientation */ - final_data = ancilData; + if ( ((air_data & 0x8) == 0) && ((air_data & 0x2) == 2) ) { /* block in +x and no block in -x */ + final_data = final_data | 0x1; /* facing north */ + + } else if ( ((air_data & 0x2) == 0) && ((air_data & 0x8) == 8)) { + final_data = final_data | 0x3; + + } else if ( ((air_data & 0x4) == 0) && ((air_data & 0x1) == 1)) { + final_data = final_data | 0x2; + } /* else, facing west, value = 0 */ } else { - /* more than one adjacent chests! That shouldn't be - * possible! render as normal chest */ + /* more than one adjacent chests! render as normal chest */ return 0; } + return final_data; } else if ((state->block == 101) || (state->block == 102)) { /* iron bars and glass panes: - * they seem to stick to almost everything but air, + * they seem to stick to almost everything but air, but * not sure yet! Still a TODO! */ /* return check adjacent blocks with air, bit inverted */ return check_adjacent_blocks(state, x, y, z, 0) ^ 0x0f; diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index f388c49..c150101 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -131,7 +131,7 @@ class Textures(object): # a list of subdirectories to search for a given file, # after the obvious '.' - search_dirs = ['anim', 'misc', 'environment', 'item'] + search_dirs = ['anim', 'misc', 'environment'] search_zip_paths = [filename,] + [d + '/' + filename for d in search_dirs] def search_dir(base): """Search the given base dir for filename, in search_dirs.""" @@ -1610,195 +1610,50 @@ def stairs(self, blockid, data): return img -# normal, locked (used in april's fool day) and ender chests chests -@material(blockid=[54,95,130], data=range(30), transparent = True) +# normal and locked chest (locked was the one used in april fools' day) +# uses pseudo-ancildata found in iterate.c +@material(blockid=[54,95], data=range(12), solid=True) def chests(self, blockid, data): - # the first 3 bits are the orientation as stored in minecraft, - # bits 0x8 and 0x10 indicate which half of the double chest is it. + # First two bits of the pseudo data store if it's a single chest + # or it's a double chest, first half or second half (left to right). + # The last two bits store the orientation. - # first, do the rotation if needed - orientation_data = data & 7 - if self.rotation == 1: - if orientation_data == 2: data = 5 | (data & 24) - elif orientation_data == 3: data = 4 | (data & 24) - elif orientation_data == 4: data = 2 | (data & 24) - elif orientation_data == 5: data = 3 | (data & 24) - elif self.rotation == 2: - if orientation_data == 2: data = 3 | (data & 24) - elif orientation_data == 3: data = 2 | (data & 24) - elif orientation_data == 4: data = 5 | (data & 24) - elif orientation_data == 5: data = 4 | (data & 24) - elif self.rotation == 3: - if orientation_data == 2: data = 4 | (data & 24) - elif orientation_data == 3: data = 5 | (data & 24) - elif orientation_data == 4: data = 3 | (data & 24) - elif orientation_data == 5: data = 2 | (data & 24) - - if blockid in (95,130) and not data in [2,3,4,5]: return None - # iterate.c will only return the ancil data (without pseudo - # ancil data) for locked and ender chests, so only - # ancilData = 2,3,4,5 are used for this blockids - - if data & 24 == 0: - if blockid == 130: t = self.load_image("enderchest.png") - else: t = self.load_image("chest.png") - t.save("textura.png") - # the textures is no longer in terrain.png, get it from - # item/chest.png and get by cropping all the needed stuff - if t.size != (64,64): t = t.resize((64,64), Image.ANTIALIAS) - # top - top = t.crop((14,0,28,14)) - top.load() # every crop need a load, crop is a lazy operation - # see PIL manual - img = Image.new("RGBA", (16,16), self.bgcolor) - alpha_over(img,top,(1,1)) - top = img - # front - front_top = t.crop((14,14,28,19)) - front_top.load() - front_bottom = t.crop((14,34,28,43)) - front_bottom.load() - front_lock = t.crop((1,0,3,4)) - front_lock.load() - front = Image.new("RGBA", (16,16), self.bgcolor) - alpha_over(front,front_top, (1,1)) - alpha_over(front,front_bottom, (1,6)) - alpha_over(front,front_lock, (7,3)) - # left side - # left side, right side, and back are esentially the same for - # the default texture, we take it anyway just in case other - # textures make use of it. - side_l_top = t.crop((0,14,14,19)) - side_l_top.load() - side_l_bottom = t.crop((0,34,14,43)) - side_l_bottom.load() - side_l = Image.new("RGBA", (16,16), self.bgcolor) - alpha_over(side_l,side_l_top, (1,1)) - alpha_over(side_l,side_l_bottom, (1,6)) - # right side - side_r_top = t.crop((28,14,43,20)) - side_r_top.load() - side_r_bottom = t.crop((28,33,42,43)) - side_r_bottom.load() - side_r = Image.new("RGBA", (16,16), self.bgcolor) - alpha_over(side_r,side_l_top, (1,1)) - alpha_over(side_r,side_l_bottom, (1,6)) - # back - back_top = t.crop((42,14,56,18)) - back_top.load() - back_bottom = t.crop((42,33,56,43)) - back_bottom.load() - back = Image.new("RGBA", (16,16), self.bgcolor) - alpha_over(back,side_l_top, (1,1)) - alpha_over(back,side_l_bottom, (1,6)) + # No need for rotation stuff, uses pseudo data and rotates with the map - else: - # large chest - # the textures is no longer in terrain.png, get it from - # item/chest.png and get all the needed stuff - t = self.load_image("largechest.png") - if t.size != (128,64): t = t.resize((128,64), Image.ANTIALIAS) - # top - top = t.crop((14,0,44,14)) - top.load() - img = Image.new("RGBA", (32,16), self.bgcolor) - alpha_over(img,top,(1,1)) - top = img - # front - front_top = t.crop((14,14,44,18)) - front_top.load() - front_bottom = t.crop((14,33,44,43)) - front_bottom.load() - front_lock = t.crop((1,0,3,5)) - front_lock.load() - front = Image.new("RGBA", (32,16), self.bgcolor) - alpha_over(front,front_top,(1,1)) - alpha_over(front,front_bottom,(1,5)) - alpha_over(front,front_lock,(15,3)) - # left side - side_l_top = t.crop((0,14,14,18)) - side_l_top.load() - side_l_bottom = t.crop((0,33,14,43)) - side_l_bottom.load() - side_l = Image.new("RGBA", (16,16), self.bgcolor) - alpha_over(side_l,side_l_top, (1,1)) - alpha_over(side_l,side_l_bottom,(1,5)) - # right side - side_r_top = t.crop((44,14,58,18)) - side_r_top.load() - side_r_bottom = t.crop((44,33,58,43)) - side_r_bottom.load() - side_r = Image.new("RGBA", (16,16), self.bgcolor) - alpha_over(side_r,side_r_top, (1,1)) - alpha_over(side_r,side_r_bottom,(1,5)) - # back - back_top = t.crop((58,14,88,18)) - back_top.load() - back_bottom = t.crop((58,33,88,43)) - back_bottom.load() - back = Image.new("RGBA", (32,16), self.bgcolor) - alpha_over(back,back_top,(1,1)) - alpha_over(back,back_bottom,(1,5)) - + top = self.terrain_images[25] + side = self.terrain_images[26] - if data & 24 == 8: # double chest, first half - top = top.crop((0,0,16,16)) - top.load() - front = front.crop((0,0,16,16)) - front.load() - back = back.crop((0,0,16,16)) - back.load() - #~ side = side_l + if data & 12 == 0: # single chest + front = self.terrain_images[27] + back = self.terrain_images[26] - elif data & 24 == 16: # double, second half - top = top.crop((16,0,32,16)) - top.load() - front = front.crop((16,0,32,16)) - front.load() - back = back.crop((16,0,32,16)) - back.load() - #~ side = side_r + elif data & 12 == 4: # double, first half + front = self.terrain_images[41] + back = self.terrain_images[57] - else: # just in case - return None + elif data & 12 == 8: # double, second half + front = self.terrain_images[42] + back = self.terrain_images[58] - # compose the final block - img = Image.new("RGBA", (24,24), self.bgcolor) - if data & 7 == 2: # north - side = self.transform_image_side(side_r) - alpha_over(img, side, (1,7)) - back = self.transform_image_side(back) - alpha_over(img, back.transpose(Image.FLIP_LEFT_RIGHT), (11,7)) - front = self.transform_image_side(front) - top = self.transform_image_top(top.rotate(180)) - alpha_over(img, top, (0,2)) - - elif data & 7 == 3: # south - side = self.transform_image_side(side_l) - alpha_over(img, side, (1,7)) - front = self.transform_image_side(front).transpose(Image.FLIP_LEFT_RIGHT) - top = self.transform_image_top(top.rotate(180)) - alpha_over(img, top, (0,2)) - alpha_over(img, front,(11,7)) - - elif data & 7 == 4: # west - side = self.transform_image_side(side_r) - alpha_over(img, side.transpose(Image.FLIP_LEFT_RIGHT), (11,7)) - front = self.transform_image_side(front) - alpha_over(img, front,(1,7)) - top = self.transform_image_top(top.rotate(270)) - alpha_over(img, top, (0,2)) - - elif data & 7 == 5: # east - back = self.transform_image_side(back) - side = self.transform_image_side(side_l).transpose(Image.FLIP_LEFT_RIGHT) - alpha_over(img, side, (11,7)) - alpha_over(img, back, (1,7)) - top = self.transform_image_top(top.rotate(270)) - alpha_over(img, top, (0,2)) - else: # just in case - img = None + front = self.terrain_images[25] + side = self.terrain_images[25] + back = self.terrain_images[25] + + if data & 3 == 0: # facing west + img = self.build_full_block(top, None, None, side, front) + + elif data & 3 == 1: # north + img = self.build_full_block(top, None, None, front, side) + + elif data & 3 == 2: # east + img = self.build_full_block(top, None, None, side, back) + + elif data & 3 == 3: # south + img = self.build_full_block(top, None, None, back, side) + + else: + img = self.build_full_block(top, None, None, back, side) return img From f4a1c32d1a83dc824fd9ef91d51ba8f4c20c3221 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Tue, 5 Jun 2012 01:09:47 -0400 Subject: [PATCH 80/85] added sealevel option to HeightFading primitive --- docs/config.rst | 7 +++++++ overviewer_core/rendermodes.py | 4 ++++ overviewer_core/src/overviewer.h | 2 +- overviewer_core/src/primitives/height-fading.c | 6 +++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index 45db947..c4496f6 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -619,6 +619,13 @@ Nether HeightFading Draws a colored overlay on the blocks that fades them out according to their height. + + **Options** + + sealevel + sealevel of the word you're rendering. Note that the default, + 128, is usually *incorrect* for most worlds. You should + probably set this to 64. Default: 128 Depth Only renders blocks between the specified min and max heights. diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py index 382630a..5de04e6 100644 --- a/overviewer_core/rendermodes.py +++ b/overviewer_core/rendermodes.py @@ -52,6 +52,10 @@ class Nether(RenderPrimitive): class HeightFading(RenderPrimitive): name = "height-fading" + options = { + # 128 is *WRONG*, it should be 64. but we're grandfathered in for now + "sealevel": ("target sea level", 128), + } black_color = Image.new("RGB", (24,24), (0,0,0)) white_color = Image.new("RGB", (24,24), (255,255,255)) diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index af15a4d..0bca02d 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 34 +#define OVERVIEWER_EXTENSION_VERSION 35 /* Python PIL, and numpy headers */ #include diff --git a/overviewer_core/src/primitives/height-fading.c b/overviewer_core/src/primitives/height-fading.c index ae7f85b..e177492 100644 --- a/overviewer_core/src/primitives/height-fading.c +++ b/overviewer_core/src/primitives/height-fading.c @@ -20,12 +20,16 @@ typedef struct { PyObject *black_color; PyObject *white_color; + unsigned int sealevel; } PrimitiveHeightFading; static int height_fading_start(void *data, RenderState *state, PyObject *support) { PrimitiveHeightFading *self = (PrimitiveHeightFading *)data; + if (!render_mode_parse_option(support, "sealevel", "I", &(self->sealevel))) + return 1; + self->black_color = PyObject_GetAttrString(support, "black_color"); self->white_color = PyObject_GetAttrString(support, "white_color"); @@ -50,7 +54,7 @@ height_fading_draw(void *data, RenderState *state, PyObject *src, PyObject *mask PyObject *height_color = self->white_color; /* current formula requires y to be between 0 and 127, so scale it */ - y = (y * 128) / (16 * SECTIONS_PER_CHUNK); + y = (y * 128) / (2 * self->sealevel); /* negative alpha => darkness, positive => light */ alpha = (1.0 / (1 + expf((70 - y) / 11.0))) * 0.6 - 0.55; From 05bfaaf9676693a7acce0c37799ed3e0edbe393a Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Tue, 5 Jun 2012 23:18:15 -0400 Subject: [PATCH 81/85] added slime overlay, colors chunks green if slimes can spawn --- docs/config.rst | 5 + overviewer.py | 2 +- overviewer_core/rendermodes.py | 3 + overviewer_core/src/iterate.c | 3 +- overviewer_core/src/overviewer.h | 3 +- .../src/primitives/overlay-slime.c | 126 ++++++++++++++++++ overviewer_core/tileset.py | 9 +- overviewer_core/world.py | 7 +- 8 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 overviewer_core/src/primitives/overlay-slime.c diff --git a/docs/config.rst b/docs/config.rst index c4496f6..ff84568 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -715,6 +715,11 @@ SpawnOverlay this on top of other modes, or on top of ClearBase to create a pure overlay. +SlimeOverlay + Color the map green in chunks where slimes can spawn. Either use + this on top of other modes, or on top of ClearBase to create a + pure overlay. + MineralOverlay Color the map according to what minerals can be found underneath. Either use this on top of other modes, or on top of diff --git a/overviewer.py b/overviewer.py index 1e7b4d1..ab4e4ac 100755 --- a/overviewer.py +++ b/overviewer.py @@ -423,7 +423,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces. render['name'] = render_name # perhaps a hack. This is stored here for the asset manager tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist","showspawn", "overlay","base"]) tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this - tset = tileset.TileSet(rset, assetMrg, tex, tileSetOpts, tileset_dir) + tset = tileset.TileSet(w, rset, assetMrg, tex, tileSetOpts, tileset_dir) tilesets.append(tset) # Do tileset preprocessing here, before we start dispatching jobs diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py index 5de04e6..d854d0f 100644 --- a/overviewer_core/rendermodes.py +++ b/overviewer_core/rendermodes.py @@ -195,6 +195,9 @@ class Overlay(RenderPrimitive): class SpawnOverlay(Overlay): name = "overlay-spawn" +class SlimeOverlay(Overlay): + name = "overlay-slime" + class MineralOverlay(Overlay): name = "overlay-mineral" options = { diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index bbc9446..6411f90 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -432,7 +432,6 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { PyObject* chunk_render(PyObject *self, PyObject *args) { RenderState state; - PyObject *regionset; PyObject *modeobj; PyObject *blockmap; @@ -453,7 +452,7 @@ chunk_render(PyObject *self, PyObject *args) { PyObject *t = NULL; - if (!PyArg_ParseTuple(args, "OiiiOiiOO", &state.regionset, &state.chunkx, &state.chunky, &state.chunkz, &state.img, &xoff, &yoff, &modeobj, &state.textures)) + if (!PyArg_ParseTuple(args, "OOiiiOiiOO", &state.world, &state.regionset, &state.chunkx, &state.chunky, &state.chunkz, &state.img, &xoff, &yoff, &modeobj, &state.textures)) return NULL; /* set up the render mode */ diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index 0bca02d..caefdeb 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 35 +#define OVERVIEWER_EXTENSION_VERSION 36 /* Python PIL, and numpy headers */ #include @@ -88,6 +88,7 @@ typedef struct { } ChunkData; typedef struct { /* the regionset object, and chunk coords */ + PyObject *world; PyObject *regionset; int chunkx, chunky, chunkz; diff --git a/overviewer_core/src/primitives/overlay-slime.c b/overviewer_core/src/primitives/overlay-slime.c new file mode 100644 index 0000000..f4abfe8 --- /dev/null +++ b/overviewer_core/src/primitives/overlay-slime.c @@ -0,0 +1,126 @@ +/* + * This file is part of the Minecraft Overviewer. + * + * Minecraft Overviewer is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Minecraft Overviewer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the Overviewer. If not, see . + */ + +#include "overlay.h" +#include + +typedef struct { + /* inherits from overlay */ + RenderPrimitiveOverlay parent; + long seed; +} RenderPrimitiveSlime; + +/* + * random_* are a re-implementation of java's Random() class + * since Minecraft's slime algorithm depends on it + * http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html + */ + +static void random_set_seed(long *seed, long new_seed) { + *seed = (new_seed ^ 0x5deece66dL) & ((1L << 48) - 1); +} + +static int random_next(long *seed, int bits) { + *seed = (*seed * 0x5deece66dL + 0xbL) & ((1L << 48) - 1); + return (int)(*seed >> (48 - bits)); +} + +static int random_next_int(long *seed, int n) { + int bits, val; + + if (n <= 0) { + /* invalid */ + return 0; + } + + if ((n & -n) == n) { + /* n is a power of two */ + return (int)((n * (long)random_next(seed, 31)) >> 31); + } + + do { + bits = random_next(seed, 31); + val = bits % n; + } while (bits - val + (n - 1) < 0); + return val; +} + +static int is_slime(long map_seed, long chunkx, long chunkz) { + /* lots of magic numbers, but they're all correct! I swear! */ + long seed; + random_set_seed(&seed, map_seed + (chunkx * chunkx * 0x4c1906L) + (chunkx * 0x5ac0dbL) + (chunkz * chunkz * 0x4307a7L) + (chunkz * 0x5f24fL) ^ 0x3ad8025fL); + return (random_next_int(&seed, 10) == 0); +} + +static void get_color(void *data, RenderState *state, + unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { + RenderPrimitiveSlime *self = (RenderPrimitiveSlime *)data; + + /* set a nice, pretty green color */ + *r = 40; + *g = 230; + *b = 40; + + /* default to no overlay, until told otherwise */ + *a = 0; + + if (is_slime(self->seed, state->chunkx, state->chunkz)) { + /* slimes can spawn! */ + *a = 240; + } +} + +static int +overlay_slime_start(void *data, RenderState *state, PyObject *support) { + RenderPrimitiveSlime *self; + PyObject *pyseed; + + /* first, chain up */ + int ret = primitive_overlay.start(data, state, support); + if (ret != 0) + return ret; + + /* now do custom initializations */ + self = (RenderPrimitiveSlime *)data; + self->parent.get_color = get_color; + + pyseed = PyObject_GetAttrString(state->world, "seed"); + if (!pyseed) + return 1; + self->seed = PyInt_AsLong(pyseed); + Py_DECREF(pyseed); + if (PyErr_Occurred()) + return 1; + + return 0; +} + +static void +overlay_slime_finish(void *data, RenderState *state) { + /* chain up */ + primitive_overlay.finish(data, state); +} + +RenderPrimitiveInterface primitive_overlay_slime = { + "overlay-slime", + sizeof(RenderPrimitiveSlime), + overlay_slime_start, + overlay_slime_finish, + NULL, + NULL, + overlay_draw, +}; diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index e5f10e0..629f59f 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -164,12 +164,14 @@ class TileSet(object): """ - def __init__(self, regionsetobj, assetmanagerobj, texturesobj, options, outputdir): + def __init__(self, worldobj, regionsetobj, assetmanagerobj, texturesobj, options, outputdir): """Construct a new TileSet object with the given configuration options dictionary. options is a dictionary of configuration parameters (strings mapping to values) that are interpreted by the rendering engine. + + worldobj is the World object that regionsetobj is from. regionsetobj is the RegionSet object that is used to render the tiles. @@ -269,6 +271,7 @@ class TileSet(object): """ self.options = options + self.world = worldobj self.regionset = regionsetobj self.am = assetmanagerobj self.textures = texturesobj @@ -356,7 +359,7 @@ class TileSet(object): # Only pickle the initial state. Don't pickle anything resulting from the # do_preprocessing step def __getstate__(self): - return self.regionset, self.am, self.textures, self.options, self.outputdir + return self.world, self.regionset, self.am, self.textures, self.options, self.outputdir def __setstate__(self, state): self.__init__(*state) @@ -946,7 +949,7 @@ class TileSet(object): # draw the chunk! try: - c_overviewer.render_loop(self.regionset, chunkx, chunky, + c_overviewer.render_loop(self.world, self.regionset, chunkx, chunky, chunkz, tileimg, xpos, ypos, self.options['rendermode'], self.textures) except nbt.CorruptionError: diff --git a/overviewer_core/world.py b/overviewer_core/world.py index bce578a..af76a49 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -136,7 +136,12 @@ class World(object): except KeyError: # but very old ones might not? so we'll just go with the world dir name if they don't self.name = os.path.basename(os.path.realpath(self.worlddir)) - + + try: + # level.dat also has a RandomSeed attribute + self.seed = data['RandomSeed'] + except KeyError: + self.seed = 0 # oh well # TODO figure out where to handle regionlists From 40482de34c2fa0e5ab8268e47e5804a9f9c55e29 Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Thu, 7 Jun 2012 10:30:52 -0700 Subject: [PATCH 82/85] Update docs to remove warnings about overlays being not implemented. --- docs/config.rst | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index ff84568..4694d22 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -557,11 +557,7 @@ values. The valid configuration keys are listed below. ``overlay`` This specifies which renders that this render will be displayed on top of. - It should be a list of renders. - - .. warning:: - - At this time, this feature is not fully implemented. + It should be a list of other renders. **Default:** ``[]`` (an empty list) @@ -705,11 +701,6 @@ ClearBase Forces the background to be transparent. Use this in place of Base for rendering pure overlays. - .. warning:: - - Overlays are currently not functional in this branch of code. We are - working on them. Please inquire in :ref:`IRC` for more information. - SpawnOverlay Color the map red in areas where monsters can spawn. Either use this on top of other modes, or on top of ClearBase to create a From 721ab679895d5f4a17d0efc4745d342644ee418b Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Thu, 7 Jun 2012 14:58:56 -0700 Subject: [PATCH 83/85] Fix an issue with baked in overlays not having any alpha, tested with non baked in too and no change there --- overviewer_core/src/overviewer.h | 2 +- overviewer_core/src/primitives/overlay.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index caefdeb..97a5a2e 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -26,7 +26,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 36 +#define OVERVIEWER_EXTENSION_VERSION 37 /* Python PIL, and numpy headers */ #include diff --git a/overviewer_core/src/primitives/overlay.c b/overviewer_core/src/primitives/overlay.c index 0645a4d..1e02489 100644 --- a/overviewer_core/src/primitives/overlay.c +++ b/overviewer_core/src/primitives/overlay.c @@ -82,8 +82,8 @@ overlay_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyOb /* do the overlay */ if (a > 0) { - alpha_over(state->img, self->white_color, self->facemask_top, state->imgx, state->imgy + increment, 0, 0); - tint_with_mask(state->img, r, g, b, a, self->facemask_top, state->imgx, state->imgy + increment, 0, 0); + alpha_over_full(state->img, self->white_color, self->facemask_top, a/255.f, state->imgx, state->imgy + increment, 0, 0); + tint_with_mask(state->img, r, g, b, 255, self->facemask_top, state->imgx, state->imgy + increment, 0, 0); } } From 25cb1f19c9cedf8c1f07bd0ef7aeb55864c397aa Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 7 Jun 2012 19:56:11 -0400 Subject: [PATCH 84/85] if render_loop raises a general exception, it's considered fatal now this is how some misconfiguration is caught, so *some* must be fatal --- overviewer_core/tileset.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index 629f59f..c2a8bec 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -17,6 +17,7 @@ import itertools import logging import os import os.path +import sys import shutil import random import functools @@ -957,8 +958,9 @@ class TileSet(object): # get_chunk() logging.debug("Skipping the render of corrupt chunk at %s,%s and moving on.", chunkx, chunkz) except Exception, e: - logging.warning("Could not render chunk %s,%s for some reason. I'm going to ignore this and continue", chunkx, chunkz) - logging.debug("Full error was:", exc_info=1) + logging.error("Could not render chunk %s,%s for some reason. This is likely a render primitive option error.", chunkx, chunkz) + logging.error("Full error was:", exc_info=1) + sys.exit(1) ## Semi-handy routine for debugging the drawing routine ## Draw the outline of the top of the chunk From c17e33a81043e814b80b531fb74fbb326e6fcc4f Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 7 Jun 2012 20:17:49 -0400 Subject: [PATCH 85/85] skip_sides in lighting_is_face_occluded is now correctly named switched a conditional, but should still be fixed as per 75f80dae954c565cb62089b10cc7c075f4bf1ea1 --- overviewer_core/src/primitives/lighting.c | 6 +++--- overviewer_core/src/primitives/smooth-lighting.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/overviewer_core/src/primitives/lighting.c b/overviewer_core/src/primitives/lighting.c index 79895a4..317ac98 100644 --- a/overviewer_core/src/primitives/lighting.c +++ b/overviewer_core/src/primitives/lighting.c @@ -202,7 +202,7 @@ lighting_is_face_occluded(RenderState *state, int skip_sides, int x, int y, int /* this face isn't visible, so don't draw anything */ return 1; } - } else if (skip_sides) { + } else if (!skip_sides) { unsigned short block = get_data(state, BLOCKS, x, y, z); if (!is_transparent(block)) { /* the same thing but for adjacent chunks, this solves an @@ -242,8 +242,8 @@ lighting_start(void *data, RenderState *state, PyObject *support) { RenderPrimitiveLighting* self; self = (RenderPrimitiveLighting *)data; - /* skip sides by default */ - self->skip_sides = 1; + /* don't skip sides by default */ + self->skip_sides = 0; if (!render_mode_parse_option(support, "strength", "f", &(self->strength))) return 1; diff --git a/overviewer_core/src/primitives/smooth-lighting.c b/overviewer_core/src/primitives/smooth-lighting.c index 8840253..6e3da54 100644 --- a/overviewer_core/src/primitives/smooth-lighting.c +++ b/overviewer_core/src/primitives/smooth-lighting.c @@ -143,7 +143,7 @@ do_shading_with_rule(RenderPrimitiveSmoothLighting *self, RenderState *state, st int cz = state->z + face.dz; /* first, check for occlusion if the block is in the local chunk */ - if (lighting_is_face_occluded(state, 1, cx, cy, cz)) + if (lighting_is_face_occluded(state, 0, cx, cy, cz)) return; /* calculate the lighting colors for each point */