0

Reimplement signs/POIs

This commit is contained in:
Andrew Chin
2012-03-03 23:42:05 -05:00
parent 3fd9b82108
commit 6b77d54555
8 changed files with 346 additions and 14 deletions

132
genPOI.py Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/python2
'''
genPOI.py
Scans regionsets for TileEntities and Entities, filters them, and writes out
POI/marker info.
A markerSet is list of POIs to display on a tileset. It has a display name,
and a group name.
markersDB.js holds a list of POIs in each group
markers.js holds a list of which markerSets are attached to each tileSet
'''
import os
import logging
import json
from optparse import OptionParser
from overviewer_core import logger
from overviewer_core import nbt
from overviewer_core import configParser, world
helptext = """
%prog --config=<config file>"""
logger.configure()
def handleSigns(rset, outputdir, render, rname):
if hasattr(rset, "_pois"):
return
logging.info("Looking for entities in %r", rset)
filters = render['markers']
rset._pois = dict(TileEntities=[], Entities=[])
for (x,z,mtime) in rset.iterate_chunks():
data = rset.get_chunk(x,z)
rset._pois['TileEntities'] += data['TileEntities']
rset._pois['Entities'] += data['Entities']
def main():
parser = OptionParser(usage=helptext)
parser.add_option("--config", dest="config", action="store", help="Specify the config file to use.")
options, args = parser.parse_args()
if not options.config:
parser.print_help()
return
# Parse the config file
mw_parser = configParser.MultiWorldParser()
mw_parser.parse(options.config)
try:
config = mw_parser.get_validated_config()
except Exception:
logging.exception("An error was encountered with your configuration. See the info below.")
return 1
destdir = config['outputdir']
# saves us from creating the same World object over and over again
worldcache = {}
markersets = set()
markers = dict()
for rname, render in config['renders'].iteritems():
try:
worldpath = config['worlds'][render['world']]
except KeyError:
logging.error("Render %s's world is '%s', but I could not find a corresponding entry in the worlds dictionary.",
rname, render['world'])
return 1
render['worldname_orig'] = render['world']
render['world'] = worldpath
# find or create the world object
if (render['world'] not in worldcache):
w = world.World(render['world'])
worldcache[render['world']] = w
else:
w = worldcache[render['world']]
rset = w.get_regionset(render['dimension'])
if rset == None: # indicates no such dimension was found:
logging.error("Sorry, you requested dimension '%s' for %s, but I couldn't find it", render['dimension'], render_name)
return 1
for f in render['markers']:
markersets.add((f, rset))
name = f.__name__ + hex(hash(f))[-4:] + "_" + hex(hash(rset))[-4:]
try:
l = markers[rname]
l.append(dict(groupName=name, displayName = f.__doc__))
except KeyError:
markers[rname] = [dict(groupName=name, displayName=f.__doc__),]
handleSigns(rset, os.path.join(destdir, rname), render, rname)
logging.info("Done scanning regions")
logging.info("Writing out javascript files")
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=[])
for poi in rset._pois['TileEntities']:
if flter(poi):
markerSetDict[name]['raw'].append(poi)
#print markerSetDict
with open(os.path.join(destdir, "markersDB.js"), "w") as output:
output.write("var markersDB=")
json.dump(markerSetDict, output, indent=2)
output.write(";\n");
with open(os.path.join(destdir, "markers.js"), "w") as output:
output.write("var markers=")
json.dump(markers, output, indent=2)
output.write(";\n");
with open(os.path.join(destdir, "baseMarkers.js"), "w") as output:
output.write("overviewer.util.injectMarkerScript('markersDB.js');\n")
output.write("overviewer.util.injectMarkerScript('markers.js');\n")
output.write("overviewer.collections.haveSigns=true;\n")
logging.info("Done")
if __name__ == "__main__":
main()

View File

@@ -42,11 +42,6 @@ directory.
self.outputdir = outputdir self.outputdir = outputdir
self.renders = dict() self.renders = dict()
# stores Points Of Interest to be mapped with markers
# This is a dictionary of lists of dictionaries
# Each regionset's name is a key in this dictionary
self.POI = dict()
# look for overviewerConfig in self.outputdir # look for overviewerConfig in self.outputdir
try: try:
with open(os.path.join(self.outputdir, "overviewerConfig.js")) as c: with open(os.path.join(self.outputdir, "overviewerConfig.js")) as c:
@@ -65,13 +60,6 @@ directory.
return dict() return dict()
def found_poi(self, regionset, poi_type, contents, chunkX, chunkY):
if regionset.name not in self.POI.keys():
POI[regionset.name] = []
# TODO based on the type, so something
POI[regionset.name].append
def initialize(self, tilesets): def initialize(self, tilesets):
"""Similar to finalize() but calls the tilesets' get_initial_data() """Similar to finalize() but calls the tilesets' get_initial_data()
instead of get_persistent_data() to compile the generated javascript instead of get_persistent_data() to compile the generated javascript
@@ -152,6 +140,12 @@ directory.
global_assets = os.path.join(util.get_program_path(), "web_assets") global_assets = os.path.join(util.get_program_path(), "web_assets")
mirror_dir(global_assets, self.outputdir) mirror_dir(global_assets, self.outputdir)
# write a dummy baseMarkers.js if none exists
if not os.path.exists(os.path.join(self.outputdir, "baseMarkers.js")):
with open(os.path.join(self.outputdir, "baseMarkers.js"), "w") as f:
f.write("// if you wants signs, please see genPOI.py\n");
# create overviewer.js from the source js files # create overviewer.js from the source js files
js_src = os.path.join(util.get_program_path(), "overviewer_core", "data", "js_src") js_src = os.path.join(util.get_program_path(), "overviewer_core", "data", "js_src")
if not os.path.isdir(js_src): if not os.path.isdir(js_src):

View File

@@ -29,7 +29,14 @@ overviewer.collections = {
*/ */
'infoWindow': null, 'infoWindow': null,
'worldViews': [] 'worldViews': [],
'haveSigns': false,
/**
* Hold the raw marker data for each tilest
*/
'markerInfo': {}
}; };
overviewer.classes = { overviewer.classes = {

View File

@@ -58,6 +58,11 @@ overviewer.util = {
var coordsdiv = new overviewer.views.CoordboxView({tagName: 'DIV'}); var coordsdiv = new overviewer.views.CoordboxView({tagName: 'DIV'});
coordsdiv.render(); coordsdiv.render();
if (overviewer.collections.haveSigns) {
var signs = new overviewer.views.SignControlView();
signs.registerEvents(signs);
}
// Update coords on mousemove // Update coords on mousemove
google.maps.event.addListener(overviewer.map, 'mousemove', function (event) { google.maps.event.addListener(overviewer.map, 'mousemove', function (event) {
coordsdiv.updateCoords(event.latLng); coordsdiv.updateCoords(event.latLng);
@@ -102,6 +107,7 @@ overviewer.util = {
overviewer.map.setZoom(zoom); overviewer.map.setZoom(zoom);
} }
}); });
var worldSelector = new overviewer.views.WorldSelectorView({tagName:'DIV'}); var worldSelector = new overviewer.views.WorldSelectorView({tagName:'DIV'});
@@ -116,15 +122,43 @@ overviewer.util = {
// Jump to the hash if given // Jump to the hash if given
overviewer.util.initHash(); overviewer.util.initHash();
overviewer.util.initializeMarkers();
/* /*
overviewer.util.initializeMapTypes(); overviewer.util.initializeMapTypes();
overviewer.util.initializeMap(); overviewer.util.initializeMap();
overviewer.util.initializeMarkers();
overviewer.util.initializeRegions(); overviewer.util.initializeRegions();
overviewer.util.createMapControls(); overviewer.util.createMapControls();
*/ */
}, },
'injectMarkerScript': function(url) {
var m = document.createElement('script'); m.type = 'text/javascript'; m.async = false;
m.src = url;
var s = document.getElementsByTagName('script')[0]; s.parentNode.appendChild(m);
},
'initializeMarkers': function() {
return;
},
'createMarkerInfoWindow': function(marker) {
var windowContent = '<div class="infoWindow"><img src="' + marker.icon +
'"/><p>' + marker.title.replace(/\n/g,'<br/>') + '</p></div>';
var infowindow = new google.maps.InfoWindow({
'content': windowContent
});
google.maps.event.addListener(marker, 'click', function() {
if (overviewer.collections.infoWindow) {
overviewer.collections.infoWindow.close();
}
infowindow.open(overviewer.map, marker);
overviewer.collections.infoWindow = infowindow;
});
},
/** /**
* This adds some methods to these classes because Javascript is stupid * This adds some methods to these classes because Javascript is stupid
* and this seems like the best way to avoid re-creating the same methods * and this seems like the best way to avoid re-creating the same methods

View File

@@ -219,3 +219,159 @@ overviewer.views.GoogleMapView = Backbone.View.extend({
}); });
/**
* SignControlView
*/
overviewer.views.SignControlView = Backbone.View.extend({
/** SignControlView::initialize
*/
initialize: function(opts) {
$(this.el).addClass("customControl");
overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(this.el);
},
registerEvents: function(me) {
google.maps.event.addListener(overviewer.map, 'maptypeid_changed', function(event) {
overviewer.mapView.updateCurrentTileset();
me.render();
// hide markers, if necessary
// for each markerSet, check:
// if the markerSet isnot part of this tileset, hide all of the markers
var curMarkerSet = overviewer.mapView.options.currentTileSet.attributes.path;
console.log("sign control things %r is the new current tileset", curMarkerSet);
var dataRoot = markers[curMarkerSet];
var groupsForThisTileSet = jQuery.map(dataRoot, function(elem, i) { return elem.groupName;})
for (markerSet in markersDB) {
console.log("checking to see if markerset %r should be hidden (is it not in %r)", markerSet, groupsForThisTileSet);
if (jQuery.inArray(markerSet, groupsForThisTileSet) == -1){
// hide these
console.log("nope, going to hide these");
if (markersDB[markerSet].created) {
jQuery.each(markersDB[markerSet].raw, function(i, elem) {
//console.log("attempting to set %r to visible(%r)", elem.markerObj, checked);
elem.markerObj.setVisible(false);
});
}
} else {
//make sure the checkbox is checked
//TODO fix this
//console.log("trying to checkbox for " + markerSet);
//console.log($("[_mc_groupname=" + markerSet + "]"));
}
}
});
},
/**
* SignControlView::render
*/
render: function() {
var curMarkerSet = overviewer.mapView.options.currentTileSet.attributes.path;
console.log(curMarkerSet);
//var dataRoot = overviewer.collections.markerInfo[curMarkerSet];
var dataRoot = markers[curMarkerSet];
console.log(dataRoot);
// before re-building this control, we need to hide all currently displayed signs
// TODO
this.el.innerHTML=""
var controlText = document.createElement('DIV');
controlText.innerHTML = "Signs";
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='';
// add the functionality to toggle visibility of the items
$(controlText).click(function() {
$(controlBorder).toggleClass('top-active');
$(dropdownDiv).toggle();
});
// add some menus
for (i in dataRoot) {
var group = dataRoot[i];
console.log(group);
this.addItem({label: group.displayName, groupName:group.groupName, action:function(this_item, checked) {
console.log("%r is %r", this_item, checked);
console.log("group name is %r", this_item.groupName);
jQuery.each(markersDB[this_item.groupName].raw, function(i, elem) {
//console.log("attempting to set %r to visible(%r)", elem.markerObj, checked);
elem.markerObj.setVisible(checked);
});
}});
}
iconURL = overviewerConfig.CONST.image.signMarker;
//dataRoot['markers'] = [];
//
for (i in dataRoot) {
var groupName = dataRoot[i].groupName;
if (!markersDB[groupName].created) {
for (j in markersDB[groupName].raw) {
var entity = markersDB[groupName].raw[j];
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.Text1 + "\n" + entity.Text2 + "\n" + entity.Text3 + "\n" + entity.Text4),
'icon': iconURL,
'visible': false
});
if (entity['id'] == 'Sign') {
overviewer.util.createMarkerInfoWindow(marker);
}
console.log("Added marker for %r", entity);
jQuery.extend(entity, {markerObj: marker});
}
markersDB[groupName].created = true;
}
}
},
addItem: function(item) {
var itemDiv = document.createElement('div');
var itemInput = document.createElement('input');
itemInput.type='checkbox';
// give it a name
$(itemInput).data('label',item.label);
$(itemInput).attr("_mc_groupname", item.groupName);
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');
if(item.icon) {
textNode.innerHTML = '<img width="15" height="15" src="' +
item.icon + '">' + item.label + '<br/>';
} else {
textNode.innerHTML = item.label + '<br/>';
}
itemDiv.appendChild(textNode);
},
});

View File

@@ -17,6 +17,7 @@
<script type="text/javascript" src="backbone.js"></script> <script type="text/javascript" src="backbone.js"></script>
<script type="text/javascript" src="overviewerConfig.js"></script> <script type="text/javascript" src="overviewerConfig.js"></script>
<script type="text/javascript" src="overviewer.js"></script> <script type="text/javascript" src="overviewer.js"></script>
<script type="text/javascript" src="baseMarkers.js"></script>
</head> </head>

View File

@@ -75,6 +75,7 @@ renders = Setting(required=True, default=util.OrderedDict(),
"rerenderprob": Setting(required=True, validator=validateFloat, default=0), "rerenderprob": Setting(required=True, validator=validateFloat, default=0),
"crop": Setting(required=False, validator=validateCrop, default=None), "crop": Setting(required=False, validator=validateCrop, default=None),
"changelist": Setting(required=False, validator=validateStr, default=None), "changelist": Setting(required=False, validator=validateStr, default=None),
"markers": Setting(required=False, validator=validateMarkers, default=[]),
# Remove this eventually (once people update their configs) # Remove this eventually (once people update their configs)
"worldname": Setting(required=False, default=None, "worldname": Setting(required=False, default=None,

View File

@@ -43,6 +43,13 @@ def checkBadEscape(s):
fixed = True fixed = True
return (fixed, fixed_string) return (fixed, fixed_string)
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)
return filterlist
def validateWorldPath(worldpath): def validateWorldPath(worldpath):
_, worldpath = checkBadEscape(worldpath) _, worldpath = checkBadEscape(worldpath)