diff --git a/src/main/java/org/dynmap/regions/TownyConfigHandler.java b/src/main/java/org/dynmap/regions/TownyConfigHandler.java index 5f4865d..d5aab6f 100644 --- a/src/main/java/org/dynmap/regions/TownyConfigHandler.java +++ b/src/main/java/org/dynmap/regions/TownyConfigHandler.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; @@ -61,6 +62,23 @@ public class TownyConfigHandler { private static final String FLAGS[] = { "hasUpkeep", "pvp", "mobs", "public", "explosion", "fire" }; + + /** + * Find all contiguous blocks, set in target and clear in source + */ + private int floodFillTarget(TileFlags src, TileFlags dest, int x, int y) { + int cnt = 0; + if(src.getFlag(x, y)) { /* Set in src */ + src.setFlag(x, y, false); /* Clear source */ + dest.setFlag(x, y, true); /* Set in destination */ + cnt++; + cnt += floodFillTarget(src, dest, x+1, y); /* Fill adjacent blocks */ + cnt += floodFillTarget(src, dest, x-1, y); + cnt += floodFillTarget(src, dest, x, y+1); + cnt += floodFillTarget(src, dest, x, y-1); + } + return cnt; + } /** * Process data from given town file */ @@ -80,113 +98,152 @@ public class TownyConfigHandler { } /* Get block list */ String blocks = p.getProperty("townBlocks"); - /* If it doesn't start with world, we're done (town on different world) */ - if((blocks == null) || (!blocks.startsWith(wname+":"))) - return null; String[] nodes = blocks.split(";"); /* Split into list */ TileFlags blks = new TileFlags(); - ArrayList nodevals = new ArrayList(); - int minx = Integer.MAX_VALUE; - int miny = Integer.MAX_VALUE; + LinkedList nodevals = new LinkedList(); + boolean worldmatch = false; + for(String n: nodes) { + /* Is world prefix? */ int idx = n.indexOf(':'); - if(idx >= 0) n = n.substring(idx+1); + if(idx >= 0) { + String w = n.substring(0, idx); + if(w.startsWith("|")) w = w.substring(1); + worldmatch = w.equals(wname); /* See if our world */ + n = n.substring(idx+1); /* Process remainder as coordinate */ + } + if(!worldmatch) continue; String[] v = n.split(","); if(v.length == 2) { try { int[] vv = new int[] { Integer.valueOf(v[0]), Integer.valueOf(v[1]) }; blks.setFlag(vv[0], vv[1], true); nodevals.add(vv); - if(vv[0] < minx) { - minx = vv[0]; - miny = vv[1]; - } - else if((vv[0] == minx) && (vv[1] < miny)) { - miny = vv[1]; - } } catch (NumberFormatException nfx) { Log.severe("Error parsing block list in Towny - " + townfile.getPath()); return null; } } } - /* Trace outline of blocks - start from minx, miny going to x+ */ - int init_x = minx; - int init_y = miny; - int cur_x = minx+1; - int cur_y = miny; - direction dir = direction.XPLUS; - ArrayList linelist = new ArrayList(); - linelist.add(new int[] { init_x, init_y } ); // Add start point - while((cur_x != init_x) || (cur_y != init_y)) { - switch(dir) { - case XPLUS: /* Segment in X+ direction */ - if(!blks.getFlag(cur_x+1, cur_y)) { /* Right turn? */ - linelist.add(new int[] { cur_x+1, cur_y }); /* Finish line */ - dir = direction.YPLUS; /* Change direction */ + /* If nothing in this world, skip */ + if(nodevals.size() == 0) + return null; + /* Loop through until we don't find more areas */ + ArrayList[]> polygons = new ArrayList[]>(); + while(nodevals != null) { + LinkedList ournodes = null; + LinkedList newlist = null; + TileFlags ourblks = null; + int minx = Integer.MAX_VALUE; + int miny = Integer.MAX_VALUE; + for(int[] node : nodevals) { + if((ourblks == null) && blks.getFlag(node[0], node[1])) { /* Node still in map? */ + ourblks = new TileFlags(); /* Create map for shape */ + ournodes = new LinkedList(); + floodFillTarget(blks, ourblks, node[0], node[1]); /* Copy shape */ + ournodes.add(node); /* Add it to our node list */ + minx = node[0]; miny = node[1]; + } + /* If shape found, and we're in it, add to our node list */ + else if((ourblks != null) && (ourblks.getFlag(node[0], node[1]))) { + ournodes.add(node); + if(node[0] < minx) { + minx = node[0]; miny = node[1]; } - else if(!blks.getFlag(cur_x+1, cur_y-1)) { /* Straight? */ - cur_x++; + else if((node[0] == minx) && (node[1] < miny)) { + miny = node[1]; } - else { /* Left turn */ - linelist.add(new int[] { cur_x+1, cur_y }); /* Finish line */ - dir = direction.YMINUS; - cur_x++; cur_y--; - } - break; - case YPLUS: /* Segment in Y+ direction */ - if(!blks.getFlag(cur_x, cur_y+1)) { /* Right turn? */ - linelist.add(new int[] { cur_x+1, cur_y+1 }); /* Finish line */ - dir = direction.XMINUS; /* Change direction */ - } - else if(!blks.getFlag(cur_x+1, cur_y+1)) { /* Straight? */ - cur_y++; - } - else { /* Left turn */ - linelist.add(new int[] { cur_x+1, cur_y+1 }); /* Finish line */ - dir = direction.XPLUS; - cur_x++; cur_y++; - } - break; - case XMINUS: /* Segment in X- direction */ - if(!blks.getFlag(cur_x-1, cur_y)) { /* Right turn? */ - linelist.add(new int[] { cur_x, cur_y+1 }); /* Finish line */ - dir = direction.YMINUS; /* Change direction */ - } - else if(!blks.getFlag(cur_x-1, cur_y+1)) { /* Straight? */ - cur_x--; - } - else { /* Left turn */ - linelist.add(new int[] { cur_x, cur_y+1 }); /* Finish line */ - dir = direction.YPLUS; - cur_x--; cur_y++; - } - break; - case YMINUS: /* Segment in Y- direction */ - if(!blks.getFlag(cur_x, cur_y-1)) { /* Right turn? */ - linelist.add(new int[] { cur_x, cur_y }); /* Finish line */ - dir = direction.XPLUS; /* Change direction */ - } - else if(!blks.getFlag(cur_x-1, cur_y-1)) { /* Straight? */ - cur_y--; - } - else { /* Left turn */ - linelist.add(new int[] { cur_x, cur_y }); /* Finish line */ - dir = direction.XMINUS; - cur_x--; cur_y--; - } - break; + } + else { /* Else, keep it in the list for the next polygon */ + if(newlist == null) newlist = new LinkedList(); + newlist.add(node); + } } + nodevals = newlist; /* Replace list (null if no more to process) */ + if(ourblks == null) continue; /* Nothing found, skip to end */ + /* Trace outline of blocks - start from minx, miny going to x+ */ + int init_x = minx; + int init_y = miny; + int cur_x = minx; + int cur_y = miny; + direction dir = direction.XPLUS; + ArrayList linelist = new ArrayList(); + linelist.add(new int[] { init_x, init_y } ); // Add start point + while((cur_x != init_x) || (cur_y != init_y) || (dir != direction.YMINUS)) { + switch(dir) { + case XPLUS: /* Segment in X+ direction */ + if(!ourblks.getFlag(cur_x+1, cur_y)) { /* Right turn? */ + linelist.add(new int[] { cur_x+1, cur_y }); /* Finish line */ + dir = direction.YPLUS; /* Change direction */ + } + else if(!ourblks.getFlag(cur_x+1, cur_y-1)) { /* Straight? */ + cur_x++; + } + else { /* Left turn */ + linelist.add(new int[] { cur_x+1, cur_y }); /* Finish line */ + dir = direction.YMINUS; + cur_x++; cur_y--; + } + break; + case YPLUS: /* Segment in Y+ direction */ + if(!ourblks.getFlag(cur_x, cur_y+1)) { /* Right turn? */ + linelist.add(new int[] { cur_x+1, cur_y+1 }); /* Finish line */ + dir = direction.XMINUS; /* Change direction */ + } + else if(!ourblks.getFlag(cur_x+1, cur_y+1)) { /* Straight? */ + cur_y++; + } + else { /* Left turn */ + linelist.add(new int[] { cur_x+1, cur_y+1 }); /* Finish line */ + dir = direction.XPLUS; + cur_x++; cur_y++; + } + break; + case XMINUS: /* Segment in X- direction */ + if(!ourblks.getFlag(cur_x-1, cur_y)) { /* Right turn? */ + linelist.add(new int[] { cur_x, cur_y+1 }); /* Finish line */ + dir = direction.YMINUS; /* Change direction */ + } + else if(!ourblks.getFlag(cur_x-1, cur_y+1)) { /* Straight? */ + cur_x--; + } + else { /* Left turn */ + linelist.add(new int[] { cur_x, cur_y+1 }); /* Finish line */ + dir = direction.YPLUS; + cur_x--; cur_y++; + } + break; + case YMINUS: /* Segment in Y- direction */ + if(!ourblks.getFlag(cur_x, cur_y-1)) { /* Right turn? */ + linelist.add(new int[] { cur_x, cur_y }); /* Finish line */ + dir = direction.XPLUS; /* Change direction */ + } + else if(!ourblks.getFlag(cur_x-1, cur_y-1)) { /* Straight? */ + cur_y--; + } + else { /* Left turn */ + linelist.add(new int[] { cur_x, cur_y }); /* Finish line */ + dir = direction.XMINUS; + cur_x--; cur_y--; + } + break; + } + } + @SuppressWarnings("unchecked") + Map[] coordlist = new Map[linelist.size()]; + for(int i = 0; i < linelist.size(); i++) { + coordlist[i] = new HashMap(); + coordlist[i].put("x", linelist.get(i)[0] * townblocksize); + coordlist[i].put("z", linelist.get(i)[1] * townblocksize); + } + polygons.add(coordlist); } @SuppressWarnings("unchecked") - Map[] coordlist = new Map[linelist.size()]; - for(int i = 0; i < linelist.size(); i++) { - coordlist[i] = new HashMap(); - coordlist[i].put("x", linelist.get(i)[0] * townblocksize); - coordlist[i].put("z", linelist.get(i)[1] * townblocksize); - } + Map[][] polylist = new Map[polygons.size()][]; + polygons.toArray(polylist); rslt = new HashMap(); - rslt.put("points", coordlist); + rslt.put("points", polylist); + /* Add other data */ String mayor = p.getProperty("mayor"); if(mayor != null) rslt.put("mayor", mayor); diff --git a/web/js/regions.js b/web/js/regions.js index 716b4de..9170f97 100644 --- a/web/js/regions.js +++ b/web/js/regions.js @@ -53,44 +53,38 @@ componentconstructors['regions'] = function(dynmap, configuration) { } function create3DBoxLayer(maxx, minx, maxy, miny, maxz, minz, style) { - return new L.FeatureGroup([ - new L.Polygon([ + return new L.MultiPolygon([ + [ latlng(minx,miny,minz), latlng(maxx,miny,minz), latlng(maxx,miny,maxz), latlng(minx,miny,maxz) - ], style), - new L.Polygon([ + ],[ latlng(minx,maxy,minz), latlng(maxx,maxy,minz), latlng(maxx,maxy,maxz), latlng(minx,maxy,maxz) - ], style), - new L.Polygon([ + ],[ latlng(minx,miny,minz), latlng(minx,maxy,minz), latlng(maxx,maxy,minz), latlng(maxx,miny,minz) - ], style), - new L.Polygon([ + ],[ latlng(maxx,miny,minz), latlng(maxx,maxy,minz), latlng(maxx,maxy,maxz), latlng(maxx,miny,maxz) - ], style), - new L.Polygon([ + ],[ latlng(minx,miny,maxz), latlng(minx,maxy,maxz), latlng(maxx,maxy,maxz), latlng(maxx,miny,maxz) - ], style), - new L.Polygon([ + ],[ latlng(minx,miny,minz), latlng(minx,maxy,minz), latlng(minx,maxy,maxz), latlng(minx,miny,maxz) - ], style) - ]); + ]], style); } function create2DBoxLayer(maxx, minx, maxy, miny, maxz, minz, style) { @@ -117,12 +111,12 @@ componentconstructors['regions'] = function(dynmap, configuration) { sidelist[1] = botlist[i]; sidelist[2] = botlist[(i+1)%xarray.length]; sidelist[3] = toplist[(i+1)%xarray.length]; - polylist[i] = new L.Polygon(sidelist, style); + polylist[i] = sidelist; } - polylist[xarray.length] = new L.Polygon(botlist, style); - polylist[xarray.length+1] = new L.Polygon(toplist, style); + polylist[xarray.length] = botlist; + polylist[xarray.length+1] = toplist; - return new L.FeatureGroup(polylist); + return new L.MultiPolygon(polylist, style); } function create2DOutlineLayer(xarray, maxy, miny, zarray, style) { diff --git a/web/js/regions_Towny.js b/web/js/regions_Towny.js index ea3a535..641dc11 100644 --- a/web/js/regions_Towny.js +++ b/web/js/regions_Towny.js @@ -1,14 +1,12 @@ regionConstructors['Towny'] = function(dynmap, configuration) { // Helper function. - function createOutlineFromRegion(name, region, outCreator) { + function createOutlineFromRegion(name, region, points, outCreator) { var xarray = []; var zarray = []; - if(region.points) { - var i; - for(i = 0; i < region.points.length; i++) { - xarray[i] = region.points[i].x; - zarray[i] = region.points[i].z; - } + var i; + for(i = 0; i < points.length; i++) { + xarray[i] = points[i].x; + zarray[i] = points[i].z; } var ymin = 64; var ymax = 65; @@ -20,14 +18,17 @@ regionConstructors['Towny'] = function(dynmap, configuration) { $.getJSON('standalone/'+regionFile, function(data) { var boxLayers = []; $.each(data, function(name, region) { - var outLayer = createOutlineFromRegion(name, region, configuration.createOutlineLayer); - if (outLayer) { - outLayer.bindPopup(configuration.createPopupContent(name, - $.extend(region, { - owners: { players: [region.mayor] }, - members: { players: [ region.residents ] } - }))); - boxLayers.push(outLayer); + var i; + for(i = 0; i < region.points.length; i++) { + var outLayer = createOutlineFromRegion(name, region, region.points[i], configuration.createOutlineLayer); + if (outLayer) { + outLayer.bindPopup(configuration.createPopupContent(name, + $.extend(region, { + owners: { players: [region.mayor] }, + members: { players: [ region.residents ] } + }))); + boxLayers.push(outLayer); + } } }); configuration.result(new L.LayerGroup(boxLayers));