From 25fcd5e8bbb3cc64adda1e6970e53ae3a9279e60 Mon Sep 17 00:00:00 2001 From: Johannes Dewender Date: Tue, 27 Mar 2012 01:44:00 +0200 Subject: [PATCH 01/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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/59] 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 e2b24a7a0f2bdd690bf651b36dd554454d7a3146 Mon Sep 17 00:00:00 2001 From: stoneLeaf Date: Tue, 10 Apr 2012 18:07:44 +0300 Subject: [PATCH 15/59] Added a new section entitled 'A dynamic config file'. It explains the use of environment variables in the config file to dynamically retrieve parameters. --- docs/config.rst | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/config.rst b/docs/config.rst index dac2c12..e256843 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -115,6 +115,53 @@ individual renders to apply to just those renders. See the ``sample_config.py`` file included in the repository for another example. +A dynamic config file +===================== + +It might be handy to dynamically retrieve parameters. For instance, if you +periodically render your last map backup which is located in a timestamped +directory, it is not convenient to edit the config file each time to fit the +new directory name. + +Using environment variables, you can easily retrieve a parameter which has +been set by, for instance, your map backup script. In this example, Overviewer is +called from a *bash* script, but it can be done from other shell scripts and +languages. + +:: + + ## The bash script + + # Setting up an environment variable that child processes will inherit + MYWORLD_DIR=/path/to/map/backup/$yourtimestamp/YourWorld + export MYWORLD_DIR + + # Running the Overviwer + overviewer.py --config=/path/to/yourConfig.py + +.. note:: + + The environment variable will only be local to the process and its child + processes. In this example, the Overviewer will be able to access the + variable since it becomes a child process. + +:: + + ## The config file + + # Importing the os python module + import os + + # Retrieving the environment variable + worlds["My world"] = os.environ['MYWORLD_DIR'] + + renders["normalrender"] = { + "world": "My world", + "title": "Normal Render of My World", + } + + outputdir = "/home/username/mcmap" + Config File Specifications ========================== From 4e7c83792805973950344e0b2d60ae93a202e9ab Mon Sep 17 00:00:00 2001 From: CounterPillow Date: Tue, 10 Apr 2012 21:30:26 +0200 Subject: [PATCH 16/59] Added documentation about optimizeimg. --- docs/config.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/config.rst b/docs/config.rst index dac2c12..dfd8450 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -360,6 +360,20 @@ values. The valid configuration keys are listed below. **Default:** ``95`` +``optimizeimg`` + This option specifies which additional tools overviewer should use to + optimize the filesize of png tiles. + The tools used must be placed somewhere, where overviewer can find them, for + example the "PATH" environment variable or a directory like /usr/bin. + This should be an integer between 0 and 3. + * ``1 - Use pngcrush`` + * ``2 - Use advdef`` + * ``3 - Use pngcrush and advdef (Not recommended)`` + Using this option may significantly increase render time, but will make + the resulting tiles smaller, with lossless image quality. + + **Default:** ``0`` + ``bgcolor`` This is the background color to be displayed behind the map. Its value should be either a string in the standard HTML color syntax or a 4-tuple in From b9217e28c8f28a27e639c9144656035df3651cd6 Mon Sep 17 00:00:00 2001 From: stoneLeaf Date: Wed, 11 Apr 2012 00:42:43 +0300 Subject: [PATCH 17/59] Improved the 'A dynamic config file' doc section. --- docs/config.rst | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index e256843..e9fd8a8 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -124,35 +124,39 @@ directory, it is not convenient to edit the config file each time to fit the new directory name. Using environment variables, you can easily retrieve a parameter which has -been set by, for instance, your map backup script. In this example, Overviewer is -called from a *bash* script, but it can be done from other shell scripts and -languages. +been set by, for instance, your map backup script. In this example, Overviewer +is called from a *bash* script, but it can be done from other shell scripts +and languages. :: - ## The bash script + #!/bin/bash - # Setting up an environment variable that child processes will inherit - MYWORLD_DIR=/path/to/map/backup/$yourtimestamp/YourWorld + ## Add these lines to your bash script + + # Setting up an environment variable that child processes will inherit. + # In this example, the map's path is not static and depends on the + # previously set $timestamp var. + MYWORLD_DIR=/path/to/map/backup/$timestamp/YourWorld export MYWORLD_DIR - # Running the Overviwer + # Running the Overviewer overviewer.py --config=/path/to/yourConfig.py .. note:: The environment variable will only be local to the process and its child - processes. In this example, the Overviewer will be able to access the - variable since it becomes a child process. + processes. The Overviewer, when run by the script, will be able to access + the variable since it becomes a child process. :: - ## The config file + ## A config file example # Importing the os python module import os - # Retrieving the environment variable + # Retrieving the environment variable set up by the bash script worlds["My world"] = os.environ['MYWORLD_DIR'] renders["normalrender"] = { From b13bbd02048c8c259b8381b533fd8e87975ba78f Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Thu, 12 Apr 2012 08:59:13 -0700 Subject: [PATCH 18/59] 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 19/59] 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 20/59] 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 21/59] 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 b7f4cc3fc9aa3e7e597e51927f61fae6d3f0bd6b Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Fri, 13 Apr 2012 09:55:30 -0700 Subject: [PATCH 22/59] Make the built in rendermodes show up on the docs table of contents --- docs/config.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.rst b/docs/config.rst index dac2c12..e0aa983 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -643,7 +643,7 @@ are referencing the previously defined list, not one of the built-in rendermodes. Built-in Rendermodes --------------------- +==================== The built-in rendermodes are nothing but pre-defined lists of rendermode primitives for your convenience. Here are their definitions:: From 85e2ac202fad83e3ddd1a06a9fc43cab5146b0f9 Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Fri, 13 Apr 2012 23:48:07 -0400 Subject: [PATCH 23/59] 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 24/59] 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 25/59] 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 26/59] 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 27/59] 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 28/59] 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 29/59] 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 30/59] 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 31/59] 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 32/59] 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 33/59] 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 34/59] 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 35/59] 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 36/59] 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 27c644d4ea66b09d4ab3f26c3bd21e0db32268fa Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Fri, 27 Apr 2012 09:19:31 -0700 Subject: [PATCH 37/59] 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 38/59] 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 39/59] 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 40/59] 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 41/59] 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 42/59] 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 59749199734a9d69717e3d9939ad5c8d9a7601b1 Mon Sep 17 00:00:00 2001 From: Richard Pastrick Date: Tue, 1 May 2012 10:59:57 -0700 Subject: [PATCH 43/59] 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 44/59] 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 45/59] 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 46/59] 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 47/59] 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 48/59] 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 49/59] 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 50/59] 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 51/59] 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 52/59] 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 53/59] 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 54/59] 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 55/59] 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 56/59] 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 57/59] 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 f395a13d98b6d40a170a3e590a5c7ad9f0ede90a Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Wed, 16 May 2012 10:15:38 -0400 Subject: [PATCH 58/59] 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 fc84f8c892448f85746453c002edea5d25a2237c Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Sat, 19 May 2012 17:13:49 -0300 Subject: [PATCH 59/59] 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"""