diff --git a/src/main/java/org/dynmap/regions/RegionHandler.java b/src/main/java/org/dynmap/regions/RegionHandler.java index a1bc373c..f260cd5d 100644 --- a/src/main/java/org/dynmap/regions/RegionHandler.java +++ b/src/main/java/org/dynmap/regions/RegionHandler.java @@ -22,8 +22,14 @@ import java.io.ByteArrayInputStream; public class RegionHandler extends FileHandler { private ConfigurationNode regions; + private String regiontype; + private TownyConfigHandler towny; public RegionHandler(ConfigurationNode regions) { this.regions = regions; + regiontype = regions.getString("name", "WorldGuard"); + if(regiontype.equals("Towny")) { + towny = new TownyConfigHandler(regions); + } } @Override protected InputStream getFileInput(String path, HttpRequest request, HttpResponse response) { @@ -37,38 +43,43 @@ public class RegionHandler extends FileHandler { Configuration regionConfig = null; File infile; String regionFile; + Map regionData; - /* If using worldpath, format is either plugins/// OR - * plugins//worlds// - */ - String regiontype = regions.getString("name", "WorldGuard"); - File basepath = new File("plugins", regiontype); - if(basepath.exists() == false) - return null; - if(regions.getBoolean("useworldpath", false)) { - regionFile = worldname + "/" + regions.getString("filename", "regions.yml"); - infile = new File(basepath, regionFile); - if(!infile.exists()) { - infile = new File(basepath, "worlds/" + regionFile); + if(regiontype.equals("Towny")) { + regionData = towny.getRegionData(worldname); + } + else { + /* If using worldpath, format is either plugins/// OR + * plugins//worlds// + */ + File basepath = new File("plugins", regiontype); + if(basepath.exists() == false) + return null; + if(regions.getBoolean("useworldpath", false)) { + regionFile = worldname + "/" + regions.getString("filename", "regions.yml"); + infile = new File(basepath, regionFile); + if(!infile.exists()) { + infile = new File(basepath, "worlds/" + regionFile); + } + } + else { /* Else, its plugins// */ + regionFile = regions.getString("filename", "regions.yml"); + infile = new File(basepath, regionFile); + } + if(infile.exists()) { + regionConfig = new Configuration(infile); + } + //File didn't exist + if(regionConfig == null) + return null; + regionConfig.load(); + /* Parse region data and store in MemoryInputStream */ + String bnode = regions.getString("basenode", "regions"); + regionData = (Map) regionConfig.getProperty(bnode); + if(regionData == null) { + Log.severe("Region data from " + infile.getPath() + " does not include basenode '" + bnode + "'"); + return null; } - } - else { /* Else, its plugins// */ - regionFile = regions.getString("filename", "regions.yml"); - infile = new File(basepath, regionFile); - } - if(infile.exists()) { - regionConfig = new Configuration(infile); - } - //File didn't exist - if(regionConfig == null) - return null; - regionConfig.load(); - /* Parse region data and store in MemoryInputStream */ - String bnode = regions.getString("basenode", "regions"); - Map regionData = (Map) regionConfig.getProperty(bnode); - if(regionData == null) { - Log.severe("Region data from " + infile.getPath() + " does not include basenode '" + bnode + "'"); - return null; } /* See if we have explicit list of regions to report - limit to this list if we do */ List idlist = regions.getStrings("visibleregions", null); diff --git a/src/main/java/org/dynmap/regions/RegionsComponent.java b/src/main/java/org/dynmap/regions/RegionsComponent.java index 278c6408..e079d611 100644 --- a/src/main/java/org/dynmap/regions/RegionsComponent.java +++ b/src/main/java/org/dynmap/regions/RegionsComponent.java @@ -20,13 +20,27 @@ import org.dynmap.web.Json; public class RegionsComponent extends ClientComponent { + private TownyConfigHandler towny; + private String regiontype; + public RegionsComponent(final DynmapPlugin plugin, final ConfigurationNode configuration) { super(plugin, configuration); // For internal webserver. String fname = configuration.getString("filename", "regions.yml"); - plugin.webServer.handlers.put("/standalone/" + fname.substring(0, fname.lastIndexOf('.')) + "_*", new RegionHandler(configuration)); + + regiontype = configuration.getString("name", "WorldGuard"); + + /* Load special handler for Towny */ + if(regiontype.equals("Towny")) { + towny = new TownyConfigHandler(configuration); + plugin.webServer.handlers.put("/standalone/towny_*", new RegionHandler(configuration)); + } + else { + plugin.webServer.handlers.put("/standalone/" + fname.substring(0, fname.lastIndexOf('.')) + "_*", new RegionHandler(configuration)); + + } // For external webserver. //Parse region file for multi world style if (configuration.getBoolean("useworldpath", false)) { @@ -34,7 +48,7 @@ public class RegionsComponent extends ClientComponent { @Override public void triggered(ClientUpdateEvent t) { World world = t.world.world; - parseRegionFile(world.getName() + "/" + configuration.getString("filename", "regions.yml"), configuration.getString("filename", "regions.yml").replace(".", "_" + world.getName() + ".yml")); + parseRegionFile(world.getName(), world.getName() + "/" + configuration.getString("filename", "regions.yml"), configuration.getString("filename", "regions.yml").replace(".", "_" + world.getName() + ".yml")); } }); } else { @@ -42,36 +56,44 @@ public class RegionsComponent extends ClientComponent { @Override public void triggered(ClientUpdateEvent t) { World world = t.world.world; - parseRegionFile(configuration.getString("filename", "regions.yml"), configuration.getString("filename", "regions.yml").replace(".", "_" + world.getName() + ".yml")); + parseRegionFile(world.getName(), configuration.getString("filename", "regions.yml"), configuration.getString("filename", "regions.yml").replace(".", "_" + world.getName() + ".yml")); } }); } } //handles parsing and writing region json files - private void parseRegionFile(String regionFile, String outputFileName) + private void parseRegionFile(String wname, String regionFile, String outputFileName) { File outputFile; org.bukkit.util.config.Configuration regionConfig = null; - String regiontype = configuration.getString("name", "WorldGuard"); - if(configuration.getBoolean("useworldpath", false)) - { - if(new File("plugins/"+configuration.getString("name", "WorldGuard"), regionFile).exists()) - regionConfig = new org.bukkit.util.config.Configuration(new File("plugins/"+regiontype, regionFile)); - else if(new File("plugins/"+regiontype+"/worlds", regionFile).exists()) - regionConfig = new org.bukkit.util.config.Configuration(new File("plugins/"+regiontype+"/worlds", regionFile)); + Map regionData; + File webWorldPath; + + if(regiontype.equals("Towny")) { + regionData = towny.getRegionData(wname); + outputFileName = "towny_" + wname + ".json"; + webWorldPath = new File(plugin.getWebPath()+"/standalone/", outputFileName); } - else - regionConfig = new org.bukkit.util.config.Configuration(new File("plugins/"+regiontype, regionFile)); - //File didn't exist - if(regionConfig == null) - return; - regionConfig.load(); + else { + if(configuration.getBoolean("useworldpath", false)) + { + if(new File("plugins/"+configuration.getString("name", "WorldGuard"), regionFile).exists()) + regionConfig = new org.bukkit.util.config.Configuration(new File("plugins/"+regiontype, regionFile)); + else if(new File("plugins/"+regiontype+"/worlds", regionFile).exists()) + regionConfig = new org.bukkit.util.config.Configuration(new File("plugins/"+regiontype+"/worlds", regionFile)); + } + else + regionConfig = new org.bukkit.util.config.Configuration(new File("plugins/"+regiontype, regionFile)); + //File didn't exist + if(regionConfig == null) + return; + regionConfig.load(); - outputFileName = outputFileName.substring(0, outputFileName.lastIndexOf("."))+".json"; - - File webWorldPath = new File(plugin.getWebPath()+"/standalone/", outputFileName); - Map regionData = (Map) regionConfig.getProperty(configuration.getString("basenode", "regions")); + regionData = (Map) regionConfig.getProperty(configuration.getString("basenode", "regions")); + outputFileName = outputFileName.substring(0, outputFileName.lastIndexOf("."))+".json"; + webWorldPath = new File(plugin.getWebPath()+"/standalone/", outputFileName); + } /* See if we have explicit list of regions to report - limit to this list if we do */ List idlist = configuration.getStrings("visibleregions", null); List hidlist = configuration.getStrings("hiddenregions", null); diff --git a/src/main/java/org/dynmap/regions/TownyConfigHandler.java b/src/main/java/org/dynmap/regions/TownyConfigHandler.java new file mode 100644 index 00000000..5f4865d8 --- /dev/null +++ b/src/main/java/org/dynmap/regions/TownyConfigHandler.java @@ -0,0 +1,208 @@ +package org.dynmap.regions; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.bukkit.World; +import org.bukkit.util.config.Configuration; +import org.dynmap.ConfigurationNode; +import org.dynmap.DynmapPlugin; +import org.dynmap.Log; +import org.dynmap.utils.TileFlags; + +public class TownyConfigHandler { + private int townblocksize; /* Size of each block - default is 16x16 */ + + public TownyConfigHandler(ConfigurationNode cfg) { + /* Find path to Towny base configuration */ + File cfgfile = new File("plugins/Towny/settings/config.yml"); + if(cfgfile.canRead() == false) { /* Can't read config */ + Log.severe("Cannot find Towny file - " + cfgfile.getPath()); + return; + } + Configuration tcfg = new Configuration(cfgfile); + tcfg.load(); + townblocksize = tcfg.getInt("town_block_size", 16); /* Get block size */ + } + /** + * Get map of attributes for given world + */ + public Map getRegionData(String wname) { + Map rslt = new HashMap(); + /* List towns directory - process all towns there */ + File towndir = new File("plugins/Towny/data/towns"); + File[] towns = towndir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".txt"); + } + }); + for(File town : towns) { + Map td = processTown(town, wname); + if(td != null) { + String fn = town.getName(); + rslt.put(fn.substring(0, fn.lastIndexOf('.')), td); + } + } + return rslt; + } + + enum direction { XPLUS, YPLUS, XMINUS, YMINUS }; + + private static final String FLAGS[] = { + "hasUpkeep", "pvp", "mobs", "public", "explosion", "fire" + }; + /** + * Process data from given town file + */ + public Map processTown(File townfile, String wname) { + Properties p = new Properties(); + FileInputStream fis = null; + Map rslt = null; + try { + fis = new FileInputStream(townfile); /* Open and load file */ + p.load(fis); + } catch (IOException iox) { + Log.severe("Error loading Towny file " + townfile.getPath()); + } finally { + if(fis != null) { + try { fis.close(); } catch (IOException iox) {} + } + } + /* 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; + for(String n: nodes) { + int idx = n.indexOf(':'); + if(idx >= 0) n = n.substring(idx+1); + 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 */ + } + else if(!blks.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(!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; + } + } + @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); + } + rslt = new HashMap(); + rslt.put("points", coordlist); + /* Add other data */ + String mayor = p.getProperty("mayor"); + if(mayor != null) rslt.put("mayor", mayor); + String nation = p.getProperty("nation"); + if(nation != null) rslt.put("nation", nation); + String assistants = p.getProperty("assistants"); + if(assistants != null) rslt.put("assistants", assistants); + String residents = p.getProperty("residents"); + if(residents != null) rslt.put("residents", residents); + Map flags = new HashMap(); + for(String f : FLAGS) { + String fval = p.getProperty(f); + if(fval != null) flags.put(f, fval); + } + rslt.put("flags", flags); + + return rslt; + } +} diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index a9d56c6e..a1e7272a 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -110,6 +110,25 @@ components: # hiddenregions: # - hiddenplace # - secretsite + #- class: org.dynmap.regions.RegionsComponent + # type: regions + # name: Towny + # use3dregions: false + # infowindow: '
%regionname%
Mayor %playerowners%
Associates %playermanagers%
Flags
%flags%
' + # regionstyle: + # strokeColor: "#FF0000" + # strokeOpacity: 0.8 + # strokeWeight: 3 + # fillColor: "#FF0000" + # fillOpacity: 0.35 + # # Optional setting to limit which regions to show, by name - if commented out, all regions are shown + # visibleregions: + # - homebase + # - miningsite + # # Optional setting to hide specific regions, by name + # hiddenregions: + # - hiddenplace + # - secretsite #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" diff --git a/web/js/regions.js b/web/js/regions.js index 6cac8ce0..63216492 100644 --- a/web/js/regions.js +++ b/web/js/regions.js @@ -115,8 +115,11 @@ componentconstructors['regions'] = function(dynmap, configuration) { popup = popup.replace('%regionname%', name); popup = popup.replace('%playerowners%', join(region.owners.players)); popup = popup.replace('%groupowners%', join(region.owners.groups)); + popup = popup.replace('%playermanagers%', join(region.associates || "")); popup = popup.replace('%playermembers%', join(members.players)); popup = popup.replace('%groupmembers%', join(members.groups)); + popup = popup.replace('%parent%', region.parent || ""); + popup = popup.replace('%priority%', region.priority || ""); var regionflags = ""; $.each(region.flags, function(name, value) { regionflags = regionflags + "" + name + ": " + value + "
"; diff --git a/web/js/regions_Towny.js b/web/js/regions_Towny.js new file mode 100644 index 00000000..cf8e4b34 --- /dev/null +++ b/web/js/regions_Towny.js @@ -0,0 +1,36 @@ +regionConstructors['Towny'] = function(dynmap, configuration) { + // Helper function. + function createOutlineFromRegion(region, 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 ymin = 64; + var ymax = 65; + + return outCreator(xarray, ymax, ymin, zarray); + } + + var regionFile = 'towny_'+configuration.worldName+'.json'; + $.getJSON('standalone/'+regionFile, function(data) { + var boxLayers = []; + $.each(data, function(name, region) { + var outLayer = createOutlineFromRegion(region, 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)); + + }); +}; \ No newline at end of file