From f4de63e85e0c450906e917c0dc0fcceef0857061 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Mon, 29 Aug 2011 10:31:04 +0800 Subject: [PATCH 01/12] Add first pass of Factions support --- .../dynmap/regions/FactionsConfigHandler.java | 284 ++++++++++++++++++ .../org/dynmap/regions/RegionHandler.java | 7 + .../org/dynmap/regions/RegionsComponent.java | 11 + src/main/resources/configuration.txt | 25 ++ web/js/regions_Factions.js | 37 +++ 5 files changed, 364 insertions(+) create mode 100644 src/main/java/org/dynmap/regions/FactionsConfigHandler.java create mode 100644 web/js/regions_Factions.js diff --git a/src/main/java/org/dynmap/regions/FactionsConfigHandler.java b/src/main/java/org/dynmap/regions/FactionsConfigHandler.java new file mode 100644 index 00000000..be47e0fd --- /dev/null +++ b/src/main/java/org/dynmap/regions/FactionsConfigHandler.java @@ -0,0 +1,284 @@ +package org.dynmap.regions; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +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; +import java.util.Set; + +import org.bukkit.ChatColor; +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; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +public class FactionsConfigHandler { + private int townblocksize = 16; + protected JSONParser parser = new JSONParser(); + private Charset cs_utf8 = Charset.forName("UTF-8"); + + public FactionsConfigHandler(ConfigurationNode cfg) { + } + /** + * Get map of attributes for given world + */ + public Map getRegionData(String wname) { + /* Load factions.json file */ + File faction = new File("plugins/Factions/factions.json"); + if(faction.canRead() == false) { /* Can't read config */ + Log.severe("Cannot find Faction file - " + faction.getPath()); + return null; + } + JSONObject fact = null; + try { + Reader inputFileReader = new InputStreamReader(new FileInputStream(faction), cs_utf8); + fact = (JSONObject) parser.parse(inputFileReader); + inputFileReader.close(); + } catch (IOException ex) { + Log.severe("Exception while reading factions.json.", ex); + } catch (ParseException ex) { + Log.severe("Exception while parsing factions.json.", ex); + } + if(fact == null) + return null; + /* Load board.json */ + File board = new File("plugins/Factions/board.json"); + if(board.canRead() == false) { /* Can't read config */ + Log.severe("Cannot find Faction file - " + board.getPath()); + return null; + } + JSONObject blocks = null; + try { + Reader inputFileReader = new InputStreamReader(new FileInputStream(board), cs_utf8); + blocks = (JSONObject) parser.parse(inputFileReader); + inputFileReader.close(); + } catch (IOException ex) { + Log.severe("Exception while reading board.json.", ex); + } catch (ParseException ex) { + Log.severe("Exception while parsing board.json.", ex); + } + if(blocks == null) + return null; + /* Get value from board.json for requested world */ + Object wb = blocks.get(wname); + if((wb == null) || (!(wb instanceof JSONObject))) { + return null; + } + JSONObject wblocks = (JSONObject)wb; + Map rslt = new HashMap(); + /* Now go through the factions list, and find outline */ + for(Object factid : fact.keySet()) { + int fid = 0; + try { + fid = Integer.valueOf(factid.toString()); + } catch (NumberFormatException nfx) { + continue; + } + JSONObject fobj = (JSONObject)fact.get(factid); /* Get faction info */ + String town = (String)fobj.get("tag"); + town = ChatColor.stripColor(town); /* Strip color */ + Map td = processFaction(wblocks, fobj, fid); + if(td != null) { + rslt.put(town, td); + } + } + return rslt; + } + + enum direction { XPLUS, YPLUS, XMINUS, YMINUS }; + + private static final String FLAGS[] = { + "open", "peaceful", "peacefulExplosionsEnabled" + }; + + /** + * 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 + */ + public Map processFaction(JSONObject blocks, JSONObject faction, int factid) { + /* Build list of nodes matching our faction ID */ + LinkedList nodevals = new LinkedList(); + TileFlags blks = new TileFlags(); + for(Object k: blocks.keySet()) { + Object fid = blocks.get(k); + int bfid = 0; + try { + bfid = Integer.valueOf(fid.toString()); + } catch (NumberFormatException nfx) { + continue; + } + if(bfid == factid) { /* Our faction? */ + String[] coords = k.toString().split(","); + if(coords.length >= 2) { + try { + int[] vv = new int[] { Integer.valueOf(coords[0]), Integer.valueOf(coords[1]) }; + blks.setFlag(vv[0], vv[1], true); + nodevals.add(vv); + } catch (NumberFormatException nfx) { + Log.severe("Error parsing Factions blocks"); + return null; + } + } + } + } + /* If nothing found for this faction, 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((node[0] == minx) && (node[1] < miny)) { + miny = node[1]; + } + } + 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[][] polylist = new Map[polygons.size()][]; + polygons.toArray(polylist); + HashMap rslt = new HashMap(); + rslt.put("points", polylist); + + /* Add other data */ + Map flags = new HashMap(); + for(String f : FLAGS) { + Object fval = faction.get(f); + if(fval != null) flags.put(f, fval.toString()); + } + rslt.put("flags", flags); + + return rslt; + } +} diff --git a/src/main/java/org/dynmap/regions/RegionHandler.java b/src/main/java/org/dynmap/regions/RegionHandler.java index f260cd5d..43711d40 100644 --- a/src/main/java/org/dynmap/regions/RegionHandler.java +++ b/src/main/java/org/dynmap/regions/RegionHandler.java @@ -24,12 +24,16 @@ public class RegionHandler extends FileHandler { private ConfigurationNode regions; private String regiontype; private TownyConfigHandler towny; + private FactionsConfigHandler factions; public RegionHandler(ConfigurationNode regions) { this.regions = regions; regiontype = regions.getString("name", "WorldGuard"); if(regiontype.equals("Towny")) { towny = new TownyConfigHandler(regions); } + else if(regiontype.equals("Factions")) { + factions = new FactionsConfigHandler(regions); + } } @Override protected InputStream getFileInput(String path, HttpRequest request, HttpResponse response) { @@ -48,6 +52,9 @@ public class RegionHandler extends FileHandler { if(regiontype.equals("Towny")) { regionData = towny.getRegionData(worldname); } + else if(regiontype.equals("Factions")) { + regionData = factions.getRegionData(worldname); + } else { /* If using worldpath, format is either plugins/// OR * plugins//worlds// diff --git a/src/main/java/org/dynmap/regions/RegionsComponent.java b/src/main/java/org/dynmap/regions/RegionsComponent.java index e079d611..8817cef1 100644 --- a/src/main/java/org/dynmap/regions/RegionsComponent.java +++ b/src/main/java/org/dynmap/regions/RegionsComponent.java @@ -21,6 +21,7 @@ import org.dynmap.web.Json; public class RegionsComponent extends ClientComponent { private TownyConfigHandler towny; + private FactionsConfigHandler factions; private String regiontype; public RegionsComponent(final DynmapPlugin plugin, final ConfigurationNode configuration) { @@ -37,6 +38,11 @@ public class RegionsComponent extends ClientComponent { towny = new TownyConfigHandler(configuration); plugin.webServer.handlers.put("/standalone/towny_*", new RegionHandler(configuration)); } + /* Load special handler for Factions */ + else if(regiontype.equals("Factions")) { + factions = new FactionsConfigHandler(configuration); + plugin.webServer.handlers.put("/standalone/factions_*", new RegionHandler(configuration)); + } else { plugin.webServer.handlers.put("/standalone/" + fname.substring(0, fname.lastIndexOf('.')) + "_*", new RegionHandler(configuration)); @@ -75,6 +81,11 @@ public class RegionsComponent extends ClientComponent { outputFileName = "towny_" + wname + ".json"; webWorldPath = new File(plugin.getWebPath()+"/standalone/", outputFileName); } + else if(regiontype.equals("Factions")) { + regionData = factions.getRegionData(wname); + outputFileName = "factions_" + wname + ".json"; + webWorldPath = new File(plugin.getWebPath()+"/standalone/", outputFileName); + } else { if(configuration.getBoolean("useworldpath", false)) { diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index ca3ea984..fce4e341 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -158,6 +158,31 @@ components: # strokeColor: "#007F00" # # Optional - make layer hidden by default # hidebydefault: true + + #- class: org.dynmap.regions.RegionsComponent + # type: regions + # name: Factions + # use3dregions: false + # infowindow: '
%regionname%
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: + # - faction1 + # - faction2 + # # Optional setting to hide specific regions, by name + # hiddenregions: + # - hiddenfaction + # # Optional per-faction overrides for regionstyle (any defined replace those in regionstyle) + # customstyle: + # faction1: + # strokeColor: "#00FF00" + # # Optional - make layer hidden by default + # hidebydefault: true #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" diff --git a/web/js/regions_Factions.js b/web/js/regions_Factions.js new file mode 100644 index 00000000..1631aee1 --- /dev/null +++ b/web/js/regions_Factions.js @@ -0,0 +1,37 @@ +regionConstructors['Factions'] = function(dynmap, configuration) { + // Helper function. + function createOutlineFromRegion(name, region, points, outCreator) { + var xarray = []; + var zarray = []; + 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; + + return outCreator(xarray, ymax, ymin, zarray, configuration.getStyle(name, region.nation)); + } + + var regionFile = 'factions_'+configuration.worldName+'.json'; + $.getJSON('standalone/'+regionFile, function(data) { + var boxLayers = []; + $.each(data, function(name, region) { + 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)); + + }); +}; \ No newline at end of file From fc1fec4af8cc1482fced55b7eb05bafed4e040d5 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Tue, 30 Aug 2011 03:21:39 +0800 Subject: [PATCH 02/12] Split renderdata (generated data) from normal block data - to help with custom block work --- .../java/org/dynmap/hdmap/HDBlockModels.java | 4 +-- .../org/dynmap/hdmap/HDPerspectiveState.java | 4 +++ .../org/dynmap/hdmap/IsoHDPerspective.java | 18 +++++++---- .../java/org/dynmap/hdmap/TexturePack.java | 23 ++++++++++---- src/main/resources/texture.txt | 30 +++++++++---------- 5 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/dynmap/hdmap/HDBlockModels.java b/src/main/java/org/dynmap/hdmap/HDBlockModels.java index f1b78e63..c0b6edfd 100644 --- a/src/main/java/org/dynmap/hdmap/HDBlockModels.java +++ b/src/main/java/org/dynmap/hdmap/HDBlockModels.java @@ -31,11 +31,11 @@ public class HDBlockModels { public static class HDScaledBlockModels { private short[][][] modelvectors; - public final short[] getScaledModel(int blocktype, int blockdata) { + public final short[] getScaledModel(int blocktype, int blockdata, int blockrenderdata) { if(modelvectors[blocktype] == null) { return null; } - return modelvectors[blocktype][blockdata]; + return modelvectors[blocktype][(blockrenderdata>=0)?blockrenderdata:blockdata]; } } diff --git a/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java b/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java index b54c26eb..f9ee74cf 100644 --- a/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java +++ b/src/main/java/org/dynmap/hdmap/HDPerspectiveState.java @@ -20,6 +20,10 @@ public interface HDPerspectiveState { * Get current block data */ int getBlockData(); + /** + * Get current block render data + */ + int getBlockRenderData(); /** * Get direction of last block step */ diff --git a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index a3fd0235..21a0b64f 100644 --- a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -95,6 +95,7 @@ public class IsoHDPerspective implements HDPerspective { private class OurPerspectiveState implements HDPerspectiveState { int blocktypeid = 0; int blockdata = 0; + int blockrenderdata = -1; int lastblocktypeid = 0; Vector3D top, bottom; int px, py; @@ -193,6 +194,10 @@ public class IsoHDPerspective implements HDPerspective { * Get current block data */ public final int getBlockData() { return blockdata; } + /** + * Get current block render data + */ + public final int getBlockRenderData() { return blockrenderdata; } /** * Get direction of last block step */ @@ -473,22 +478,23 @@ public class IsoHDPerspective implements HDPerspective { skiptoair = false; } else if(nonairhit || (blocktypeid != 0)) { + blockdata = mapiter.getBlockData(); switch(blocktypeid) { case FENCE_BLKTYPEID: /* Special case for fence - need to fake data so we can render properly */ - blockdata = generateFenceBlockData(mapiter); + blockrenderdata = generateFenceBlockData(mapiter); break; case CHEST_BLKTYPEID: /* Special case for chest - need to fake data so we can render */ - blockdata = generateChestBlockData(mapiter); + blockrenderdata = generateChestBlockData(mapiter); break; case REDSTONE_BLKTYPEID: /* Special case for redstone - fake data for wire pattern */ - blockdata = generateRedstoneWireBlockData(mapiter); + blockrenderdata = generateRedstoneWireBlockData(mapiter); break; default: - blockdata = mapiter.getBlockData(); - break; + blockrenderdata = -1; + break; } /* Look up to see if block is modelled */ - short[] model = scalemodels.getScaledModel(blocktypeid, blockdata); + short[] model = scalemodels.getScaledModel(blocktypeid, blockdata, blockrenderdata); if(model != null) { return handleSubModel(model, shaderstate, shaderdone); } diff --git a/src/main/java/org/dynmap/hdmap/TexturePack.java b/src/main/java/org/dynmap/hdmap/TexturePack.java index d87c4230..bec264d8 100644 --- a/src/main/java/org/dynmap/hdmap/TexturePack.java +++ b/src/main/java/org/dynmap/hdmap/TexturePack.java @@ -120,12 +120,15 @@ public class TexturePack { private List blockids; private int databits; private BlockTransparency bt; + private boolean userender; private static HDTextureMap[] texmaps; private static BlockTransparency transp[]; + private static boolean userenderdata[]; private static void initializeTable() { texmaps = new HDTextureMap[16*BLOCKTABLELEN]; transp = new BlockTransparency[BLOCKTABLELEN]; + userenderdata = new boolean[BLOCKTABLELEN]; HDTextureMap blank = new HDTextureMap(); for(int i = 0; i < texmaps.length; i++) texmaps[i] = blank; @@ -136,6 +139,7 @@ public class TexturePack { private HDTextureMap() { blockids = Collections.singletonList(Integer.valueOf(0)); databits = 0xFFFF; + userender = false; faces = new int[] { BLOCKINDEX_BLANK, BLOCKINDEX_BLANK, BLOCKINDEX_BLANK, BLOCKINDEX_BLANK, BLOCKINDEX_BLANK, BLOCKINDEX_BLANK }; for(int i = 0; i < texmaps.length; i++) { @@ -143,11 +147,12 @@ public class TexturePack { } } - public HDTextureMap(List blockids, int databits, int[] faces, BlockTransparency trans) { + public HDTextureMap(List blockids, int databits, int[] faces, BlockTransparency trans, boolean userender) { this.faces = faces; this.blockids = blockids; this.databits = databits; this.bt = trans; + this.userender = userender; } public void addToTable() { @@ -159,11 +164,15 @@ public class TexturePack { } } transp[blkid] = bt; /* Transparency is only blocktype based right now */ + userenderdata[blkid] = userender; /* Ditto for using render data */ } } - public static HDTextureMap getMap(int blkid, int blkdata) { - return texmaps[(blkid<<4) + blkdata]; + public static HDTextureMap getMap(int blkid, int blkdata, int blkrenderdata) { + if(userenderdata[blkid]) + return texmaps[(blkid<<4) + blkrenderdata]; + else + return texmaps[(blkid<<4) + blkdata]; } public static BlockTransparency getTransparency(int blkid) { @@ -704,6 +713,7 @@ public class TexturePack { line = line.substring(6); BlockTransparency trans = BlockTransparency.OPAQUE; String[] args = line.split(","); + boolean userenderdata = false; for(String a : args) { String[] av = a.split("="); if(av.length < 2) continue; @@ -759,12 +769,15 @@ public class TexturePack { Log.severe("Texture mapping has invalid transparency setting - " + av[1] + " - line " + rdr.getLineNumber() + " of " + txtname); } } + else if(av[0].equals("userenderdata")) { + userenderdata = av[1].equals("true"); + } } /* If no data bits, assume all */ if(databits < 0) databits = 0xFFFF; /* If we have everything, build block */ if(blkids.size() > 0) { - HDTextureMap map = new HDTextureMap(blkids, databits, faces, trans); + HDTextureMap map = new HDTextureMap(blkids, databits, faces, trans, userenderdata); map.addToTable(); cnt++; } @@ -795,7 +808,7 @@ public class TexturePack { */ public final void readColor(final HDPerspectiveState ps, final MapIterator mapiter, final Color rslt, final int blkid, final int lastblocktype, final boolean biome_shaded) { int blkdata = ps.getBlockData(); - HDTextureMap map = HDTextureMap.getMap(blkid, blkdata); + HDTextureMap map = HDTextureMap.getMap(blkid, blkdata, ps.getBlockRenderData()); BlockStep laststep = ps.getLastBlockStep(); int textid = map.faces[laststep.ordinal()]; /* Get index of texture source */ if(textid < 0) { diff --git a/src/main/resources/texture.txt b/src/main/resources/texture.txt index 96a65db7..c17fb2b9 100644 --- a/src/main/resources/texture.txt +++ b/src/main/resources/texture.txt @@ -280,35 +280,35 @@ block:id=52,allfaces=65,transparency=TRANSPARENT # Wooden stairs block:id=53,allsides=4,topbottom=4004,transparency=SEMITRANSPARENT # Chest - single, facing west -block:id=54,data=0,topbottom=25,south=26,north=26,east=26,west=27 +block:id=54,data=0,topbottom=25,south=26,north=26,east=26,west=27,userenderdata=true # Chest - single, facing south -block:id=54,data=1,topbottom=25,south=27,north=26,east=26,west=26 +block:id=54,data=1,topbottom=25,south=27,north=26,east=26,west=26,userenderdata=true # Chest - single, facing east -block:id=54,data=2,topbottom=25,south=26,north=26,east=27,west=26 +block:id=54,data=2,topbottom=25,south=26,north=26,east=27,west=26,userenderdata=true # Chest - single, facing north -block:id=54,data=3,topbottom=25,south=26,north=27,east=26,west=26 +block:id=54,data=3,topbottom=25,south=26,north=27,east=26,west=26,userenderdata=true # Chest - left side of double, facing west -block:id=54,data=4,topbottom=25,south=26,north=26,east=58,west=41 +block:id=54,data=4,topbottom=25,south=26,north=26,east=58,west=41,userenderdata=true # Chest - left side of double, facing south -block:id=54,data=5,topbottom=25,south=41,north=58,east=26,west=26 +block:id=54,data=5,topbottom=25,south=41,north=58,east=26,west=26,userenderdata=true # Chest - left side of double, facing east -block:id=54,data=6,topbottom=25,south=26,north=26,east=41,west=58 +block:id=54,data=6,topbottom=25,south=26,north=26,east=41,west=58,userenderdata=true # Chest - left side of double, facing north -block:id=54,data=7,topbottom=25,south=58,north=41,east=26,west=26 +block:id=54,data=7,topbottom=25,south=58,north=41,east=26,west=26,userenderdata=true # Chest - right side of double, facing west -block:id=54,data=8,topbottom=25,south=26,north=26,east=57,west=42 +block:id=54,data=8,topbottom=25,south=26,north=26,east=57,west=42,userenderdata=true # Chest - right side of double, facing south -block:id=54,data=9,topbottom=25,south=42,north=57,east=26,west=26 +block:id=54,data=9,topbottom=25,south=42,north=57,east=26,west=26,userenderdata=true # Chest - right side of double, facing east -block:id=54,data=10,topbottom=25,south=26,north=26,east=42,west=57 +block:id=54,data=10,topbottom=25,south=26,north=26,east=42,west=57,userenderdata=true # Chest - right side of double, facing north -block:id=54,data=11,topbottom=25,south=57,north=42,east=26,west=26 +block:id=54,data=11,topbottom=25,south=57,north=42,east=26,west=26,userenderdata=true # Redstone wire (all but NS and EW) -block:id=55,data=0,data=3,data=4,data=5,data=6,data=7,data=8,data=9,data=10,allfaces=180,transparency=TRANSPARENT +block:id=55,data=0,data=3,data=4,data=5,data=6,data=7,data=8,data=9,data=10,allfaces=180,transparency=TRANSPARENT,userenderdata=true # Redstone wire (EW) -block:id=55,data=2,allfaces=181,transparency=TRANSPARENT +block:id=55,data=2,allfaces=181,transparency=TRANSPARENT,userenderdata=true # Redstone wire (NS) -block:id=55,data=1,allfaces=4181,transparency=TRANSPARENT +block:id=55,data=1,allfaces=4181,transparency=TRANSPARENT,userenderdata=true # Diamond ore block:id=56,allfaces=50 # Diamond block From 611a9352325f66c22777917790c5f91659d3642b Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Tue, 30 Aug 2011 04:53:48 +0800 Subject: [PATCH 03/12] Fix multi-map KzedMap rendering (default cave not rendered issue) --- src/main/java/org/dynmap/kzedmap/KzedMapTile.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dynmap/kzedmap/KzedMapTile.java b/src/main/java/org/dynmap/kzedmap/KzedMapTile.java index dba01203..aabe4bad 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMapTile.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMapTile.java @@ -76,7 +76,14 @@ public class KzedMapTile extends MapTile { } public boolean render(MapChunkCache cache, String mapname) { - return map.render(cache, this, MapManager.mapman.getTileFile(this)); + boolean rslt = false; + for(MapTileRenderer r : map.renderers) { + if((mapname == null) || (r.getName().equals(mapname))) { + KzedMapTile t = new KzedMapTile(world, map, r, px, py); + rslt |= map.render(cache, t, MapManager.mapman.getTileFile(t)); + } + } + return rslt; } public List getRequiredChunks() { From d1ff472bdadf525ea109f86418062841e8ebd080 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Tue, 30 Aug 2011 10:00:05 +0800 Subject: [PATCH 04/12] Add 'sidebaropened: pinned' option to allow sidebar to be pre-pinned but support unpinning --- .../org/dynmap/ClientConfigurationComponent.java | 2 +- src/main/resources/configuration.txt | 2 +- web/js/map.js | 13 +++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/dynmap/ClientConfigurationComponent.java b/src/main/java/org/dynmap/ClientConfigurationComponent.java index 82da1775..51f3f9f7 100644 --- a/src/main/java/org/dynmap/ClientConfigurationComponent.java +++ b/src/main/java/org/dynmap/ClientConfigurationComponent.java @@ -20,7 +20,7 @@ public class ClientConfigurationComponent extends Component { s(t, "spammessage", c.getString("spammessage", "You may only chat once every %interval% seconds.")); s(t, "webprefix", unescapeString(c.getString("webprefix", "[WEB] "))); s(t, "defaultzoom", c.getInteger("defaultzoom", 0)); - s(t, "sidebaropened", c.getBoolean("sidebaropened", false)); + s(t, "sidebaropened", c.getString("sidebaropened", "false")); DynmapWorld defaultWorld = null; String defmap = null; diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index fce4e341..daac4053 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -260,7 +260,7 @@ updaterate: 2000 showplayerfacesinmenu: true -# Set sidebaropened: true to pin menu sidebar opened +# Set sidebaropened: 'true' to pin menu sidebar opened permanently, 'pinned' to default the sidebar to pinned, but allow it to unpin #sidebaropened: true joinmessage: "%playername% joined" diff --git a/web/js/map.js b/web/js/map.js index a571cdec..23a1ba47 100644 --- a/web/js/map.js +++ b/web/js/map.js @@ -145,10 +145,15 @@ DynMap.prototype = { var panel; var sidebar; var pinbutton; - if(!me.options.sidebaropened) { + + if(me.options.sidebaropened != 'true') { // false or pinned + var pincls = 'pinned' + if(me.options.sidebaropened == 'false') + pincls = ''; + sidebar = me.sidebar = $('
') - .addClass('sidebar') - .appendTo(container); + .addClass('sidebar ' + pincls) + .appendTo(container); panel = $('
') .addClass('panel') @@ -271,7 +276,7 @@ DynMap.prototype = { .append(link=$('')) .data('link', link) .appendTo(container);*/ - if(!me.options.sidebaropened) { + if(me.options.sidebaropened != 'true') { $('
') .addClass('hitbar') .appendTo(panel); From f371cff011ba0c8055806407133bfc6a22251370 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Tue, 30 Aug 2011 10:33:41 +0800 Subject: [PATCH 05/12] Add support for 'http-reponse-headers' attribute to add custom response headers --- src/main/java/org/dynmap/DynmapPlugin.java | 13 +++++++++++++ src/main/java/org/dynmap/web/HttpServer.java | 9 +++++++++ .../java/org/dynmap/web/HttpServerConnection.java | 6 ++++++ src/main/resources/configuration.txt | 5 +++++ 4 files changed, 33 insertions(+) diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 1a6b5d1d..804db87b 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -303,6 +303,19 @@ public class DynmapPlugin extends JavaPlugin { boolean checkbannedips = configuration.getBoolean("check-banned-ips", true); int maxconnections = configuration.getInteger("max-sessions", 30); if(maxconnections < 2) maxconnections = 2; + /* Load customized response headers, if any */ + ConfigurationNode custhttp = configuration.getNode("http-response-headers"); + HashMap custhdrs = new HashMap(); + if(custhttp != null) { + for(String k : custhttp.keySet()) { + String v = custhttp.getString(k); + if(v != null) { + custhdrs.put(k, v); + } + } + } + HttpServer.setCustomHeaders(custhdrs); + if(allow_symlinks) Log.verboseinfo("Web server is permitting symbolic links"); else diff --git a/src/main/java/org/dynmap/web/HttpServer.java b/src/main/java/org/dynmap/web/HttpServer.java index 841dc71c..1509c7ff 100644 --- a/src/main/java/org/dynmap/web/HttpServer.java +++ b/src/main/java/org/dynmap/web/HttpServer.java @@ -10,8 +10,10 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.logging.Logger; @@ -34,6 +36,7 @@ public class HttpServer extends Thread { private Object lock = new Object(); private HashSet active_connections = new HashSet(); private HashSet keepalive_connections = new HashSet(); + private static Map headers = new HashMap(); public HttpServer(InetAddress bindAddress, int port, boolean check_banned_ips, int max_sessions) { this.bindAddress = bindAddress; @@ -189,4 +192,10 @@ public class HttpServer extends Thread { } return false; } + public static Map getCustomHeaders() { + return headers; + } + public static void setCustomHeaders(Map hdrs) { + headers = hdrs; + } } diff --git a/src/main/java/org/dynmap/web/HttpServerConnection.java b/src/main/java/org/dynmap/web/HttpServerConnection.java index 5784fafe..a41e9763 100644 --- a/src/main/java/org/dynmap/web/HttpServerConnection.java +++ b/src/main/java/org/dynmap/web/HttpServerConnection.java @@ -111,6 +111,12 @@ public class HttpServerConnection extends Thread { out.append(field.getValue()); out.append("\r\n"); } + for(Entry custom : HttpServer.getCustomHeaders().entrySet()) { + out.append(custom.getKey()); + out.append(": "); + out.append(custom.getValue()); + out.append("\r\n"); + } out.append("\r\n"); out.flush(); } diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index daac4053..ee397ffd 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -263,6 +263,11 @@ showplayerfacesinmenu: true # Set sidebaropened: 'true' to pin menu sidebar opened permanently, 'pinned' to default the sidebar to pinned, but allow it to unpin #sidebaropened: true +# Customized HTTP response headers - add 'id: value' pairs to all HTTP response headers (internal web server only) +#http-response-headers: +# Access-Control-Allow-Origin: "my-domain.com" +# X-Custom-Header-Of-Mine: "MyHeaderValue" + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." From b9170db1c1be6369792f320bdf858ad8f82bf817 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Tue, 30 Aug 2011 13:02:52 +0800 Subject: [PATCH 06/12] Support applying background color to JPG tiles (since no transparency) --- src/main/java/org/dynmap/hdmap/HDMap.java | 49 ++++++++++++++++++- .../org/dynmap/hdmap/IsoHDPerspective.java | 22 ++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/dynmap/hdmap/HDMap.java b/src/main/java/org/dynmap/hdmap/HDMap.java index 73f1fbd5..e8f31440 100644 --- a/src/main/java/org/dynmap/hdmap/HDMap.java +++ b/src/main/java/org/dynmap/hdmap/HDMap.java @@ -28,6 +28,8 @@ public class HDMap extends MapType { private ConfigurationNode configuration; private int mapzoomout; private MapType.ImageFormat imgformat; + private int bgcolornight; + private int bgcolorday; public static final String IMGFORMAT_PNG = "png"; public static final String IMGFORMAT_JPG = "jpg"; @@ -100,7 +102,20 @@ public class HDMap extends MapType { if(imgformat == null) { Log.severe("HDMap '"+name+"' set invalid image-format: " + fmt); imgformat = ImageFormat.FORMAT_PNG; - } + } + /* Get color info */ + String c = configuration.getString("background"); + if(c != null) { + bgcolorday = bgcolornight = parseColor(c); + } + c = configuration.getString("backgroundday"); + if(c != null) { + bgcolorday = parseColor(c); + } + c = configuration.getString("backgroundnight"); + if(c != null) { + bgcolornight = parseColor(c); + } } public HDShader getShader() { return shader; } @@ -222,4 +237,36 @@ public class HDMap extends MapType { a(worldObject, "maps", o); } + + private static int parseColor(String c) { + int v = 0; + if(c.startsWith("#")) { + c = c.substring(1); + if(c.length() == 3) { /* #rgb */ + try { + v = Integer.valueOf(c, 16); + } catch (NumberFormatException nfx) { + return 0; + } + v = 0xFF000000 | ((v & 0xF00) << 12) | ((v & 0x0F0) << 8) | ((v & 0x00F) << 4); + } + else if(c.length() == 6) { /* #rrggbb */ + try { + v = Integer.valueOf(c, 16); + } catch (NumberFormatException nfx) { + return 0; + } + v = 0xFF000000 | (v & 0xFFFFFF); + } + } + return v; + } + + public int getBackgroundARGBDay() { + return bgcolorday; + } + + public int getBackgroundARGBNight() { + return bgcolornight; + } } diff --git a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index 21a0b64f..01971e88 100644 --- a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -22,6 +22,7 @@ import org.dynmap.Log; import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; +import org.dynmap.MapType.ImageFormat; import org.dynmap.TileHashManager; import org.dynmap.debug.Debug; import org.dynmap.utils.MapIterator.BlockStep; @@ -971,6 +972,9 @@ public class IsoHDPerspective implements HDPerspective { DynmapBufferedImage dayim[] = new DynmapBufferedImage[numshaders]; int[][] argb_buf = new int[numshaders][]; int[][] day_argb_buf = new int[numshaders][]; + boolean isjpg[] = new boolean[numshaders]; + int bgday[] = new int[numshaders]; + int bgnight[] = new int[numshaders]; for(int i = 0; i < numshaders; i++) { HDShader shader = shaderstate[i].getShader(); @@ -985,6 +989,9 @@ public class IsoHDPerspective implements HDPerspective { dayim[i] = DynmapBufferedImage.allocateBufferedImage(tileWidth, tileHeight); day_argb_buf[i] = dayim[i].argb_buf; } + isjpg[i] = shaderstate[i].getMap().getImageFormat() != ImageFormat.FORMAT_PNG; + bgday[i] = shaderstate[i].getMap().getBackgroundARGBDay(); + bgnight[i] = shaderstate[i].getMap().getBackgroundARGBNight(); } /* Create perspective state object */ @@ -996,6 +1003,7 @@ public class IsoHDPerspective implements HDPerspective { double ybase = tile.ty * tileHeight; boolean shaderdone[] = new boolean[numshaders]; boolean rendered[] = new boolean[numshaders]; + for(int x = 0; x < tileWidth; x++) { ps.px = x; for(int y = 0; y < tileHeight; y++) { @@ -1018,10 +1026,20 @@ public class IsoHDPerspective implements HDPerspective { rendered[i] = true; } shaderstate[i].getRayColor(rslt, 0); - argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB(); + if(isjpg[i] && rslt.isTransparent()) { + argb_buf[i][(tileHeight-y-1)*tileWidth + x] = bgnight[i]; + } + else { + argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB(); + } if(day_argb_buf[i] != null) { shaderstate[i].getRayColor(rslt, 1); - day_argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB(); + if(isjpg[i] && rslt.isTransparent()) { + day_argb_buf[i][(tileHeight-y-1)*tileWidth + x] = bgday[i]; + } + else { + day_argb_buf[i][(tileHeight-y-1)*tileWidth + x] = rslt.getARGB(); + } } } } From 85a564aa45e55bb62e0c1d2a8d7112c54b1ef5bf Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Tue, 30 Aug 2011 13:03:37 +0800 Subject: [PATCH 07/12] Handle Factions on worlds with no faction data properly --- .../org/dynmap/regions/FactionsConfigHandler.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/dynmap/regions/FactionsConfigHandler.java b/src/main/java/org/dynmap/regions/FactionsConfigHandler.java index be47e0fd..917cb807 100644 --- a/src/main/java/org/dynmap/regions/FactionsConfigHandler.java +++ b/src/main/java/org/dynmap/regions/FactionsConfigHandler.java @@ -39,11 +39,12 @@ public class FactionsConfigHandler { * Get map of attributes for given world */ public Map getRegionData(String wname) { + Map rslt = new HashMap(); /* Load factions.json file */ File faction = new File("plugins/Factions/factions.json"); if(faction.canRead() == false) { /* Can't read config */ Log.severe("Cannot find Faction file - " + faction.getPath()); - return null; + return rslt; } JSONObject fact = null; try { @@ -56,12 +57,12 @@ public class FactionsConfigHandler { Log.severe("Exception while parsing factions.json.", ex); } if(fact == null) - return null; + return rslt; /* Load board.json */ File board = new File("plugins/Factions/board.json"); if(board.canRead() == false) { /* Can't read config */ Log.severe("Cannot find Faction file - " + board.getPath()); - return null; + return rslt; } JSONObject blocks = null; try { @@ -74,14 +75,13 @@ public class FactionsConfigHandler { Log.severe("Exception while parsing board.json.", ex); } if(blocks == null) - return null; + return rslt; /* Get value from board.json for requested world */ Object wb = blocks.get(wname); if((wb == null) || (!(wb instanceof JSONObject))) { - return null; + return rslt; } JSONObject wblocks = (JSONObject)wb; - Map rslt = new HashMap(); /* Now go through the factions list, and find outline */ for(Object factid : fact.keySet()) { int fid = 0; From 56faab71e2714767678988cd82537f6db8c88403 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Tue, 30 Aug 2011 13:28:28 +0800 Subject: [PATCH 08/12] Handle Towny 0.74.0 configuration format --- src/main/java/org/dynmap/regions/TownyConfigHandler.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dynmap/regions/TownyConfigHandler.java b/src/main/java/org/dynmap/regions/TownyConfigHandler.java index 141b117c..195a26af 100644 --- a/src/main/java/org/dynmap/regions/TownyConfigHandler.java +++ b/src/main/java/org/dynmap/regions/TownyConfigHandler.java @@ -32,7 +32,12 @@ public class TownyConfigHandler { } Configuration tcfg = new Configuration(cfgfile); tcfg.load(); - String tbsize = tcfg.getNode("town").getString("town_block_size", "16"); + org.bukkit.util.config.ConfigurationNode townnode = tcfg.getNode("town"); + String tbsize = "16"; + if(townnode != null) + tbsize = townnode.getString("town_block_size", "16"); + else + tbsize = tcfg.getString("town_block_size", "16"); try { townblocksize = Integer.valueOf(tbsize); } catch (NumberFormatException nfx) { From d88763f179c24ea50ed3790b0b8c8d0b8d31f600 Mon Sep 17 00:00:00 2001 From: FrozenCow Date: Tue, 30 Aug 2011 21:16:46 +0200 Subject: [PATCH 09/12] Fixed playerfaces not showing in sidebar. --- web/js/minecraft.js | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/web/js/minecraft.js b/web/js/minecraft.js index 28038695..fabe2867 100644 --- a/web/js/minecraft.js +++ b/web/js/minecraft.js @@ -9,35 +9,10 @@ function createMinecraftHead(player,size,completed,failed) { faceImage.src = dynmap.options.tileUrl + 'faces/' + size + 'x' + size + '/' + player + '.png'; } -var playerHeads = {}; - function getMinecraftHead(player,size,completed) { - var key = player + '.' + size; - var head = playerHeads[key]; - // Synchronous - if (!completed) { - return (!head || head.working) ? null : head; - } - - // Asynchronous - if (!head) { - playerHeads[key] = { working: true, hooks: [{f:completed}] }; - createMinecraftHead(player, size, function(head) { - hooks = playerHeads[key].hooks; - playerHeads[key] = head; - var i; - for(i=0;i Date: Wed, 31 Aug 2011 07:13:59 +0800 Subject: [PATCH 10/12] Yet another face fix - hopefully got the rules on accessories right this time... --- src/main/java/org/dynmap/PlayerFaces.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/dynmap/PlayerFaces.java b/src/main/java/org/dynmap/PlayerFaces.java index 470d1038..19210b72 100644 --- a/src/main/java/org/dynmap/PlayerFaces.java +++ b/src/main/java/org/dynmap/PlayerFaces.java @@ -56,16 +56,21 @@ public class PlayerFaces { int[] faceaccessory = new int[64]; /* 8x8 of face accessory */ /* Get buffered image for face at 8x8 */ DynmapBufferedImage face8x8 = DynmapBufferedImage.allocateBufferedImage(8, 8); - int[] bgcolor = new int[1]; - img.getRGB(0, 0, 1, 1, bgcolor, 0, 1); /* Get BG color (for accessory face) */ img.getRGB(8, 8, 8, 8, face8x8.argb_buf, 0, 8); /* Read face from image */ img.getRGB(40, 8, 8, 8, faceaccessory, 0, 8); /* Read face accessory from image */ - /* Apply accessory to face: first element is transparency color so only ones not matching it */ + /* Apply accessory to face: see if anything is transparent (if so, apply accessory */ + boolean transp = false; for(int i = 0; i < 64; i++) { - if(faceaccessory[i] != bgcolor[0]) - face8x8.argb_buf[i] = faceaccessory[i]; - else if(face8x8.argb_buf[i] == bgcolor[0]) - face8x8.argb_buf[i] = 0; + if((faceaccessory[i] & 0xFF000000) == 0) { + transp = true; + break; + } + } + if(transp) { + for(int i = 0; i < 64; i++) { + if((faceaccessory[i] & 0xFF000000) != 0) + face8x8.argb_buf[i] = faceaccessory[i]; + } } /* Write 8x8 file */ File img_8x8 = new File(faces8x8dir, playername + ".png"); From dcdcdd88aa736910e06c642ef99187e5e2fd142a Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Fri, 2 Sep 2011 22:19:27 +0800 Subject: [PATCH 11/12] Prevent trap if townBlocks is undefined in towny town file --- src/main/java/org/dynmap/regions/TownyConfigHandler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/dynmap/regions/TownyConfigHandler.java b/src/main/java/org/dynmap/regions/TownyConfigHandler.java index 195a26af..e6aeb9a1 100644 --- a/src/main/java/org/dynmap/regions/TownyConfigHandler.java +++ b/src/main/java/org/dynmap/regions/TownyConfigHandler.java @@ -119,6 +119,8 @@ public class TownyConfigHandler { } /* Get block list */ String blocks = p.getProperty("townBlocks"); + if(blocks == null) /* Skip if no blocks */ + return null; String[] nodes = blocks.split(";"); /* Split into list */ TileFlags blks = new TileFlags(); LinkedList nodevals = new LinkedList(); From cdffc5824fff98caeb104f134b53787c9c37e61b Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sat, 3 Sep 2011 03:22:13 +0800 Subject: [PATCH 12/12] Fix texture rotation for NE and SW rail corners --- src/main/resources/texture.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/texture.txt b/src/main/resources/texture.txt index c17fb2b9..1ba3366c 100644 --- a/src/main/resources/texture.txt +++ b/src/main/resources/texture.txt @@ -362,11 +362,11 @@ block:id=66,data=1,top=128,bottom=128,allsides=4,transparency=TRANSPARENT # Rail - incline to south block:id=66,data=2,data=3,top=128,bottom=128,north=128,south=128,transparency=TRANSPARENT # Rails - northeast corner -block:id=66,data=6,topbottom=4112,transparency=TRANSPARENT +block:id=66,data=6,topbottom=6112,transparency=TRANSPARENT # Rails - southeast corner block:id=66,data=7,topbottom=5112,transparency=TRANSPARENT # Rails - southwest corner -block:id=66,data=8,topbottom=6112,transparency=TRANSPARENT +block:id=66,data=8,topbottom=4112,transparency=TRANSPARENT # Rails - northwest corner block:id=66,data=9,topbottom=112,transparency=TRANSPARENT # Cobblestone Stairs