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):