Towny fixes - multiple areas on multiple worlds per town

This commit is contained in:
Mike Primm 2011-08-25 11:11:31 +08:00 committed by mikeprimm
parent ff4b036c6a
commit 04cc6aba43
3 changed files with 170 additions and 118 deletions

View File

@ -7,6 +7,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -61,6 +62,23 @@ public class TownyConfigHandler {
private static final String FLAGS[] = { private static final String FLAGS[] = {
"hasUpkeep", "pvp", "mobs", "public", "explosion", "fire" "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 * Process data from given town file
*/ */
@ -80,113 +98,152 @@ public class TownyConfigHandler {
} }
/* Get block list */ /* Get block list */
String blocks = p.getProperty("townBlocks"); 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 */ String[] nodes = blocks.split(";"); /* Split into list */
TileFlags blks = new TileFlags(); TileFlags blks = new TileFlags();
ArrayList<int[]> nodevals = new ArrayList<int[]>(); LinkedList<int[]> nodevals = new LinkedList<int[]>();
int minx = Integer.MAX_VALUE; boolean worldmatch = false;
int miny = Integer.MAX_VALUE;
for(String n: nodes) { for(String n: nodes) {
/* Is world prefix? */
int idx = n.indexOf(':'); 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(","); String[] v = n.split(",");
if(v.length == 2) { if(v.length == 2) {
try { try {
int[] vv = new int[] { Integer.valueOf(v[0]), Integer.valueOf(v[1]) }; int[] vv = new int[] { Integer.valueOf(v[0]), Integer.valueOf(v[1]) };
blks.setFlag(vv[0], vv[1], true); blks.setFlag(vv[0], vv[1], true);
nodevals.add(vv); 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) { } catch (NumberFormatException nfx) {
Log.severe("Error parsing block list in Towny - " + townfile.getPath()); Log.severe("Error parsing block list in Towny - " + townfile.getPath());
return null; return null;
} }
} }
} }
/* Trace outline of blocks - start from minx, miny going to x+ */ /* If nothing in this world, skip */
int init_x = minx; if(nodevals.size() == 0)
int init_y = miny; return null;
int cur_x = minx+1; /* Loop through until we don't find more areas */
int cur_y = miny; ArrayList<Map<String,Integer>[]> polygons = new ArrayList<Map<String,Integer>[]>();
direction dir = direction.XPLUS; while(nodevals != null) {
ArrayList<int[]> linelist = new ArrayList<int[]>(); LinkedList<int[]> ournodes = null;
linelist.add(new int[] { init_x, init_y } ); // Add start point LinkedList<int[]> newlist = null;
while((cur_x != init_x) || (cur_y != init_y)) { TileFlags ourblks = null;
switch(dir) { int minx = Integer.MAX_VALUE;
case XPLUS: /* Segment in X+ direction */ int miny = Integer.MAX_VALUE;
if(!blks.getFlag(cur_x+1, cur_y)) { /* Right turn? */ for(int[] node : nodevals) {
linelist.add(new int[] { cur_x+1, cur_y }); /* Finish line */ if((ourblks == null) && blks.getFlag(node[0], node[1])) { /* Node still in map? */
dir = direction.YPLUS; /* Change direction */ ourblks = new TileFlags(); /* Create map for shape */
ournodes = new LinkedList<int[]>();
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? */ else if((node[0] == minx) && (node[1] < miny)) {
cur_x++; miny = node[1];
} }
else { /* Left turn */ }
linelist.add(new int[] { cur_x+1, cur_y }); /* Finish line */ else { /* Else, keep it in the list for the next polygon */
dir = direction.YMINUS; if(newlist == null) newlist = new LinkedList<int[]>();
cur_x++; cur_y--; newlist.add(node);
} }
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;
} }
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<int[]> linelist = new ArrayList<int[]>();
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<String,Integer>[] coordlist = new Map[linelist.size()];
for(int i = 0; i < linelist.size(); i++) {
coordlist[i] = new HashMap<String,Integer>();
coordlist[i].put("x", linelist.get(i)[0] * townblocksize);
coordlist[i].put("z", linelist.get(i)[1] * townblocksize);
}
polygons.add(coordlist);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String,Integer>[] coordlist = new Map[linelist.size()]; Map<String,Integer>[][] polylist = new Map[polygons.size()][];
for(int i = 0; i < linelist.size(); i++) { polygons.toArray(polylist);
coordlist[i] = new HashMap<String,Integer>();
coordlist[i].put("x", linelist.get(i)[0] * townblocksize);
coordlist[i].put("z", linelist.get(i)[1] * townblocksize);
}
rslt = new HashMap<String,Object>(); rslt = new HashMap<String,Object>();
rslt.put("points", coordlist); rslt.put("points", polylist);
/* Add other data */ /* Add other data */
String mayor = p.getProperty("mayor"); String mayor = p.getProperty("mayor");
if(mayor != null) rslt.put("mayor", mayor); if(mayor != null) rslt.put("mayor", mayor);

View File

@ -53,44 +53,38 @@ componentconstructors['regions'] = function(dynmap, configuration) {
} }
function create3DBoxLayer(maxx, minx, maxy, miny, maxz, minz, style) { function create3DBoxLayer(maxx, minx, maxy, miny, maxz, minz, style) {
return new L.FeatureGroup([ return new L.MultiPolygon([
new L.Polygon([ [
latlng(minx,miny,minz), latlng(minx,miny,minz),
latlng(maxx,miny,minz), latlng(maxx,miny,minz),
latlng(maxx,miny,maxz), latlng(maxx,miny,maxz),
latlng(minx,miny,maxz) latlng(minx,miny,maxz)
], style), ],[
new L.Polygon([
latlng(minx,maxy,minz), latlng(minx,maxy,minz),
latlng(maxx,maxy,minz), latlng(maxx,maxy,minz),
latlng(maxx,maxy,maxz), latlng(maxx,maxy,maxz),
latlng(minx,maxy,maxz) latlng(minx,maxy,maxz)
], style), ],[
new L.Polygon([
latlng(minx,miny,minz), latlng(minx,miny,minz),
latlng(minx,maxy,minz), latlng(minx,maxy,minz),
latlng(maxx,maxy,minz), latlng(maxx,maxy,minz),
latlng(maxx,miny,minz) latlng(maxx,miny,minz)
], style), ],[
new L.Polygon([
latlng(maxx,miny,minz), latlng(maxx,miny,minz),
latlng(maxx,maxy,minz), latlng(maxx,maxy,minz),
latlng(maxx,maxy,maxz), latlng(maxx,maxy,maxz),
latlng(maxx,miny,maxz) latlng(maxx,miny,maxz)
], style), ],[
new L.Polygon([
latlng(minx,miny,maxz), latlng(minx,miny,maxz),
latlng(minx,maxy,maxz), latlng(minx,maxy,maxz),
latlng(maxx,maxy,maxz), latlng(maxx,maxy,maxz),
latlng(maxx,miny,maxz) latlng(maxx,miny,maxz)
], style), ],[
new L.Polygon([
latlng(minx,miny,minz), latlng(minx,miny,minz),
latlng(minx,maxy,minz), latlng(minx,maxy,minz),
latlng(minx,maxy,maxz), latlng(minx,maxy,maxz),
latlng(minx,miny,maxz) latlng(minx,miny,maxz)
], style) ]], style);
]);
} }
function create2DBoxLayer(maxx, minx, maxy, miny, maxz, minz, style) { function create2DBoxLayer(maxx, minx, maxy, miny, maxz, minz, style) {
@ -117,12 +111,12 @@ componentconstructors['regions'] = function(dynmap, configuration) {
sidelist[1] = botlist[i]; sidelist[1] = botlist[i];
sidelist[2] = botlist[(i+1)%xarray.length]; sidelist[2] = botlist[(i+1)%xarray.length];
sidelist[3] = toplist[(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] = botlist;
polylist[xarray.length+1] = new L.Polygon(toplist, style); polylist[xarray.length+1] = toplist;
return new L.FeatureGroup(polylist); return new L.MultiPolygon(polylist, style);
} }
function create2DOutlineLayer(xarray, maxy, miny, zarray, style) { function create2DOutlineLayer(xarray, maxy, miny, zarray, style) {

View File

@ -1,14 +1,12 @@
regionConstructors['Towny'] = function(dynmap, configuration) { regionConstructors['Towny'] = function(dynmap, configuration) {
// Helper function. // Helper function.
function createOutlineFromRegion(name, region, outCreator) { function createOutlineFromRegion(name, region, points, outCreator) {
var xarray = []; var xarray = [];
var zarray = []; var zarray = [];
if(region.points) { var i;
var i; for(i = 0; i < points.length; i++) {
for(i = 0; i < region.points.length; i++) { xarray[i] = points[i].x;
xarray[i] = region.points[i].x; zarray[i] = points[i].z;
zarray[i] = region.points[i].z;
}
} }
var ymin = 64; var ymin = 64;
var ymax = 65; var ymax = 65;
@ -20,14 +18,17 @@ regionConstructors['Towny'] = function(dynmap, configuration) {
$.getJSON('standalone/'+regionFile, function(data) { $.getJSON('standalone/'+regionFile, function(data) {
var boxLayers = []; var boxLayers = [];
$.each(data, function(name, region) { $.each(data, function(name, region) {
var outLayer = createOutlineFromRegion(name, region, configuration.createOutlineLayer); var i;
if (outLayer) { for(i = 0; i < region.points.length; i++) {
outLayer.bindPopup(configuration.createPopupContent(name, var outLayer = createOutlineFromRegion(name, region, region.points[i], configuration.createOutlineLayer);
$.extend(region, { if (outLayer) {
owners: { players: [region.mayor] }, outLayer.bindPopup(configuration.createPopupContent(name,
members: { players: [ region.residents ] } $.extend(region, {
}))); owners: { players: [region.mayor] },
boxLayers.push(outLayer); members: { players: [ region.residents ] }
})));
boxLayers.push(outLayer);
}
} }
}); });
configuration.result(new L.LayerGroup(boxLayers)); configuration.result(new L.LayerGroup(boxLayers));