diff --git a/configuration.txt b/configuration.txt index f12252b5..20e94a60 100644 --- a/configuration.txt +++ b/configuration.txt @@ -75,7 +75,7 @@ worlds: renderers: - class: org.dynmap.kzedmap.DefaultTileRenderer prefix: nt - maximumheight: 64 + maximumheight: 127 colorscheme: default web: diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 0a950e1e..c9f731b1 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -115,6 +115,10 @@ public class DynmapPlugin extends JavaPlugin { } registerEvents(); + + /* Print version info */ + PluginDescriptionFile pdfFile = this.getDescription(); + log.info("[dynmap] version " + pdfFile.getVersion() + " is enabled" ); } public void loadWebserver() { @@ -157,9 +161,7 @@ public class DynmapPlugin extends JavaPlugin { } catch (IOException e) { log.severe("Failed to start WebServer on " + bindAddress + ":" + port + "!"); } - /* Print version info */ - PluginDescriptionFile pdfFile = this.getDescription(); - log.info("[dynmap] version " + pdfFile.getVersion() + " is enabled" ); + } public void onDisable() { @@ -405,6 +407,8 @@ public class DynmapPlugin extends JavaPlugin { public void webChat(String name, String message) { mapManager.pushUpdate(new Client.ChatMessage("web", name, message)); log.info("[WEB]" + name + ": " + message); - getServer().broadcastMessage("[WEB]" + name + ": " + message); + /* Let HeroChat take a look - only broadcast to players if it doesn't handle it */ + if(hchand.sendWebMessageToHeroChat(name, message) == false) + getServer().broadcastMessage("[WEB]" + name + ": " + message); } } diff --git a/src/main/java/org/dynmap/HeroChatHandler.java b/src/main/java/org/dynmap/HeroChatHandler.java index 5afb1d72..3f84a7d9 100644 --- a/src/main/java/org/dynmap/HeroChatHandler.java +++ b/src/main/java/org/dynmap/HeroChatHandler.java @@ -22,6 +22,7 @@ public class HeroChatHandler { private List hcchannels; private String hcwebinputchannel; + private HeroChatChannel hcwebinputchan; private DynmapPlugin plugin; private class OurPluginListener extends ServerListener { @@ -39,10 +40,8 @@ public class HeroChatHandler { /* Reflection-based access wrapper for ChannelChatEvent from HeroChat */ private static class HeroChatChannelChatEvent { private static Class channelchatevent; - private static Method getchannel; private static Method getsource; private static Method getmessage; - private static Method iscancelled; private static boolean isgood = false; private Event evt; @@ -51,14 +50,8 @@ public class HeroChatHandler { try { channelchatevent = Class .forName("com.herocraftonline.dthielke.herochat.event.ChannelChatEvent"); - getchannel = channelchatevent.getMethod("getChannel", - new Class[0]); - getsource = channelchatevent.getMethod("getSource", - new Class[0]); - getmessage = channelchatevent.getMethod("getMessage", - new Class[0]); - iscancelled = channelchatevent.getMethod("isCancelled", - new Class[0]); + getsource = channelchatevent.getMethod("getSource", new Class[0]); + getmessage = channelchatevent.getMethod("getMessage", new Class[0]); isgood = true; } catch (ClassNotFoundException cnfx) { } catch (NoSuchMethodException nsmx) { @@ -74,18 +67,6 @@ public class HeroChatHandler { return channelchatevent.isInstance(evt); } - public HeroChatChannel getChannel() { - try { - Object o; - o = getchannel.invoke(evt); - if (o != null) { - return new HeroChatChannel(o); - } - } catch (Exception x) { - } - return null; - } - public String getSource() { try { return (String) getsource.invoke(evt); @@ -101,6 +82,49 @@ public class HeroChatHandler { return null; } } + } + + /* Reflection-based access wrapper for ChannelEvent from HeroChat */ + private static class HeroChatChannelEvent { + private static Class channelevent; + private static Method getchannel; + private static Method iscancelled; + private static boolean isgood = false; + private Event evt; + + @SuppressWarnings("unchecked") + public static boolean initialize() { + try { + channelevent = Class + .forName("com.herocraftonline.dthielke.herochat.event.ChannelEvent"); + getchannel = channelevent.getMethod("getChannel", new Class[0]); + iscancelled = channelevent.getMethod("isCancelled", new Class[0]); + isgood = true; + } catch (ClassNotFoundException cnfx) { + } catch (NoSuchMethodException nsmx) { + } + return isgood; + } + + public HeroChatChannelEvent(Event evt) { + this.evt = evt; + } + + public static boolean isInstance(Event evt) { + return channelevent.isInstance(evt); + } + + public HeroChatChannel getChannel() { + try { + Object o; + o = getchannel.invoke(evt); + if (o != null) { + return new HeroChatChannel(o); + } + } catch (Exception x) { + } + return null; + } public boolean isCancelled() { try { @@ -115,6 +139,8 @@ public class HeroChatHandler { private static class HeroChatChannel { private static Class channel; private static Method getname; + private static Method getnick; + private static Method sendmessage; private static boolean isgood = false; private Object chan; @@ -123,10 +149,14 @@ public class HeroChatHandler { try { channel = Class .forName("com.herocraftonline.dthielke.herochat.channels.Channel"); - getname = channel.getMethod("getName", new Class[0]); + getname = channel.getMethod("getName"); + getnick = channel.getMethod("getNick", new Class[0]); + sendmessage = channel.getMethod("sendMessage", new Class[] { + String.class, String.class, String.class, boolean.class } ); isgood = true; } catch (ClassNotFoundException cnfx) { } catch (NoSuchMethodException nsmx) { + System.out.println(nsmx); } return isgood; } @@ -135,10 +165,6 @@ public class HeroChatHandler { this.chan = chan; } - public static boolean isInstance(Object obj) { - return channel.isInstance(obj); - } - public String getName() { try { return (String) getname.invoke(chan); @@ -146,6 +172,21 @@ public class HeroChatHandler { return null; } } + + public String getNick() { + try { + return (String) getnick.invoke(chan); + } catch (Exception x) { + return null; + } + } + + public void sendMessage(String source, String msg, String format, boolean sentByPlayer) { + try { + sendmessage.invoke(chan, source, msg, format, sentByPlayer); + } catch (Exception x) { + } + } } private class OurEventListener extends CustomEventListener { @@ -154,16 +195,32 @@ public class HeroChatHandler { */ @Override public void onCustomEvent(Event event) { - if (HeroChatChannelChatEvent.isInstance(event)) { - HeroChatChannelChatEvent cce = new HeroChatChannelChatEvent( - event); - if (cce.isCancelled()) + if (HeroChatChannelEvent.isInstance(event)) { + HeroChatChannelEvent ce = new HeroChatChannelEvent(event); + /* Snoop for our web channel - we'll need it, and we'll see it before it matters, + * since anyone that joins the channel will give us an event (and reflection on + * the plugin class to get the manager didn't work, due to a dependency on the IRC + * plugin that may not be present....) + */ + HeroChatChannel c = ce.getChannel(); + /* If channel name or nickname matches out web channel, remember it */ + if((c != null) && (hcwebinputchannel != null) && + ((c.getName().equals(hcwebinputchannel)) || + c.getNick().equals(hcwebinputchannel))) { + hcwebinputchan = c; + } + if (ce.isCancelled()) return; - HeroChatChannel c = cce.getChannel(); - if (hcchannels.contains(c.getName())) { - plugin.mapManager.pushUpdate(new Client.ChatMessage( - "player", "[" + c.getName() + "] " + if (HeroChatChannelChatEvent.isInstance(event)) { + HeroChatChannelChatEvent cce = new HeroChatChannelChatEvent( + event); + /* Match on name or nickname of channel */ + if (hcchannels.contains(c.getName()) || + hcchannels.contains(c.getNick())) { + plugin.mapManager.pushUpdate(new Client.ChatMessage( + "player", "[" + c.getNick() + "] " + cce.getSource(), cce.getMessage())); + } } } } @@ -188,16 +245,38 @@ public class HeroChatHandler { private void activateHeroChat(Plugin herochat) { if (HeroChatChannelChatEvent.initialize() == false) { - log.severe("[dynmap] Cannot load HeroChat event class!"); + log.severe("[dynmap] Cannot load HeroChat chat event class!"); return; } if (HeroChatChannel.initialize() == false) { log.severe("[dynmap] Cannot load HeroChat channel class!"); return; } + if (HeroChatChannelEvent.initialize() == false) { + log.severe("[dynmap] Cannot load HeroChat channel event class!"); + return; + } + /* Register event handler */ plugin.getServer().getPluginManager().registerEvent(Event.Type.CUSTOM_EVENT, new OurEventListener(), Event.Priority.Monitor, plugin); log.info("[dynmap] HeroChat integration active"); } + /** + * Send message from web to appropriate HeroChat channel + * @param sender - sender ID + * @param message - message + * @return true if herochat is handling this, false if not + */ + public boolean sendWebMessageToHeroChat(String sender, String message) { + if(hcwebinputchannel != null) { /* Are we handling them? */ + if(hcwebinputchan != null) { /* Have we seen it yet? Maybe no if nobody has logged on or + * joined it, but then who would see it anyway? + */ + hcwebinputchan.sendMessage(sender, message, "{default}", false); + } + return true; + } + return false; + } } diff --git a/src/main/java/org/dynmap/UpdateQueue.java b/src/main/java/org/dynmap/UpdateQueue.java index 368c987d..995a57c5 100644 --- a/src/main/java/org/dynmap/UpdateQueue.java +++ b/src/main/java/org/dynmap/UpdateQueue.java @@ -11,10 +11,11 @@ public class UpdateQueue { private static final int maxUpdateAge = 120000; - public synchronized void pushUpdate(Object obj) { - long now = System.currentTimeMillis(); - long deadline = now - maxUpdateAge; + public void pushUpdate(Object obj) { synchronized (lock) { + /* Do inside lock - prevent delay between time and actual work */ + long now = System.currentTimeMillis(); + long deadline = now - maxUpdateAge; ListIterator i = updateQueue.listIterator(0); while (i.hasNext()) { Update u = i.next(); @@ -27,11 +28,11 @@ public class UpdateQueue { private ArrayList tmpupdates = new ArrayList(); - public synchronized Object[] getUpdatedObjects(long since) { - long now = System.currentTimeMillis(); - long deadline = now - maxUpdateAge; + public Object[] getUpdatedObjects(long since) { Object[] updates; synchronized (lock) { + long now = System.currentTimeMillis(); + long deadline = now - maxUpdateAge; tmpupdates.clear(); Iterator it = updateQueue.descendingIterator(); while (it.hasNext()) { diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index acdc49c0..32d6d90c 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -11,6 +11,7 @@ import javax.imageio.ImageIO; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.World.Environment; import org.dynmap.Client; import org.dynmap.ColorScheme; import org.dynmap.DynmapChunk; @@ -22,10 +23,17 @@ import org.dynmap.debug.Debug; public class FlatMap extends MapType { private String prefix; private ColorScheme colorScheme; - + private int maximumHeight = 127; + public FlatMap(Map configuration) { prefix = (String) configuration.get("prefix"); colorScheme = ColorScheme.getScheme((String) configuration.get("colorscheme")); + Object o = configuration.get("maximumheight"); + if (o != null) { + maximumHeight = Integer.parseInt(String.valueOf(o)); + if (maximumHeight > 127) + maximumHeight = 127; + } } @Override @@ -68,6 +76,7 @@ public class FlatMap extends MapType { public boolean render(MapTile tile, File outputFile) { FlatMapTile t = (FlatMapTile) tile; World w = t.getWorld(); + boolean isnether = (w.getEnvironment() == Environment.NETHER) && (maximumHeight == 127); boolean rendered = false; BufferedImage im = new BufferedImage(t.size, t.size, BufferedImage.TYPE_INT_RGB); @@ -79,17 +88,40 @@ public class FlatMap extends MapType { for (int y = 0; y < t.size; y++) { int mx = x + t.x * t.size; int mz = y + t.y * t.size; - int my = w.getHighestBlockYAt(mx, mz) - 1; - int blockType = w.getBlockTypeIdAt(mx, my, mz); - byte data = 0; - if(colorScheme.datacolors[blockType] != null) { /* If data colored */ - data = w.getBlockAt(mx, my, mz).getData(); + int my; + int blockType; + if(isnether) { + /* Scan until we hit air */ + my = 127; + while((blockType = w.getBlockTypeIdAt(mx, my, mz)) != 0) { + my--; + if(my < 0) { /* Solid - use top */ + my = 127; + blockType = w.getBlockTypeIdAt(mx, my, mz); + break; + } + } + if(blockType == 0) { /* Hit air - now find non-air */ + while((blockType = w.getBlockTypeIdAt(mx, my, mz)) == 0) { + my--; + if(my < 0) { + my = 0; + break; + } + } + } + } + else { + my = w.getHighestBlockYAt(mx, mz) - 1; + if(my > maximumHeight) my = maximumHeight; + blockType = w.getBlockTypeIdAt(mx, my, mz); + } + byte data = 0; + Color[] colors = colorScheme.colors[blockType]; + if(colorScheme.datacolors[blockType] != null) { + data = w.getBlockAt(mx, my, mz).getData(); + colors = colorScheme.datacolors[blockType][data]; } - Color[] colors; - if(data != 0) - colors = colorScheme.datacolors[blockType][data]; - else - colors = colorScheme.colors[blockType]; if (colors == null) continue; Color c = colors[0]; @@ -103,7 +135,7 @@ public class FlatMap extends MapType { // Defines the 'step' in coloring. float step = 10 / 128.0f; - + // The step applied to height. float scale = ((int)(height/step))*step; @@ -135,19 +167,19 @@ public class FlatMap extends MapType { final MapTile mtile = tile; final BufferedImage img = im; MapManager.mapman.enqueueImageWrite(new Runnable() { - public void run() { - Debug.debug("saving image " + fname.getPath()); - try { - ImageIO.write(img, "png", fname); - } catch (IOException e) { - Debug.error("Failed to save image: " + fname.getPath(), e); - } catch (java.lang.NullPointerException e) { - Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e); - } - img.flush(); - MapManager.mapman.pushUpdate(mtile.getWorld(), - new Client.Tile(mtile.getFilename())); - } + public void run() { + Debug.debug("saving image " + fname.getPath()); + try { + ImageIO.write(img, "png", fname); + } catch (IOException e) { + Debug.error("Failed to save image: " + fname.getPath(), e); + } catch (java.lang.NullPointerException e) { + Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e); + } + img.flush(); + MapManager.mapman.pushUpdate(mtile.getWorld(), + new Client.Tile(mtile.getFilename())); + } }); return rendered; diff --git a/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java b/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java index afdb1db7..7a5ee9d4 100644 --- a/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java @@ -12,14 +12,20 @@ public class CaveTileRenderer extends DefaultTileRenderer { } @Override - protected Color scan(World world, int x, int y, int z, int seq) { + protected Color scan(World world, int x, int y, int z, int seq, boolean isnether) { boolean air = true; - + for (;;) { if (y < 0) return translucent; int id = world.getBlockTypeIdAt(x, y, z); + if(isnether) { /* Make ceiling into air in nether */ + if(id != 0) + id = 0; + else + isnether = false; + } switch (seq) { case 0: diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index 3b486df2..6fa68dbc 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -12,7 +12,9 @@ import java.util.Map; import javax.imageio.ImageIO; +import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.World.Environment; import org.dynmap.Client; import org.dynmap.ColorScheme; import org.dynmap.MapManager; @@ -28,25 +30,6 @@ public class DefaultTileRenderer implements MapTileRenderer { protected HashSet highlightBlocks = new HashSet(); protected Color highlightColor = new Color(255, 0, 0); - private static final Color[] woolshades = { - Color.WHITE, - Color.ORANGE, - Color.MAGENTA, - new Color(51,204,255), - Color.YELLOW, - new Color(102,255,102), - Color.PINK, - Color.GRAY, - Color.LIGHT_GRAY, - Color.CYAN, - new Color(255,0,255), - Color.BLUE, - new Color(102,51,51), - Color.GREEN, - Color.RED, - Color.BLACK - }; - @Override public String getName() { return name; @@ -65,6 +48,7 @@ public class DefaultTileRenderer implements MapTileRenderer { public boolean render(KzedMapTile tile, File outputFile) { World world = tile.getWorld(); + boolean isnether = (world.getEnvironment() == Environment.NETHER); BufferedImage im = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); WritableRaster r = im.getRaster(); @@ -74,8 +58,12 @@ public class DefaultTileRenderer implements MapTileRenderer { int iy = maximumHeight; int iz = KzedMap.anchorz + tile.px / 2 - tile.py / 2 + ((127-maximumHeight)/2); + /* Don't mess with existing height-clipped renders */ + if(maximumHeight < 127) + isnether = false; + int jx, jz; - + int x, y; /* draw the map */ @@ -84,8 +72,8 @@ public class DefaultTileRenderer implements MapTileRenderer { jz = iz; for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) { - Color c1 = scan(world, jx, iy, jz, 0); - Color c2 = scan(world, jx, iy, jz, 2); + Color c1 = scan(world, jx, iy, jz, 0, isnether); + Color c2 = scan(world, jx, iy, jz, 2, isnether); isempty = isempty && c1 == translucent && c2 == translucent; r.setPixel(x, y, new int[] { c1.getRed(), @@ -107,10 +95,10 @@ public class DefaultTileRenderer implements MapTileRenderer { jz = iz - 1; for (x = KzedMap.tileWidth - 1; x >= 0; x -= 2) { - Color c1 = scan(world, jx, iy, jz, 2); + Color c1 = scan(world, jx, iy, jz, 2, isnether); jx++; jz++; - Color c2 = scan(world, jx, iy, jz, 0); + Color c2 = scan(world, jx, iy, jz, 0, isnether); isempty = isempty && c1 == translucent && c2 == translucent; r.setPixel(x, y, new int[] { c1.getRed(), @@ -132,100 +120,112 @@ public class DefaultTileRenderer implements MapTileRenderer { final File fname = outputFile; final KzedMapTile mtile = tile; final BufferedImage img = im; - final KzedZoomedMapTile zmtile = new KzedZoomedMapTile(mtile.getWorld(), - (KzedMap) mtile.getMap(), mtile); - final File zoomFile = MapManager.mapman.getTileFile(zmtile); - - MapManager.mapman.enqueueImageWrite(new Runnable() { - public void run() { - doFileWrites(fname, mtile, img, zmtile, zoomFile); - } + final KzedZoomedMapTile zmtile = new KzedZoomedMapTile(mtile.getWorld(), + (KzedMap) mtile.getMap(), mtile); + final File zoomFile = MapManager.mapman.getTileFile(zmtile); + + MapManager.mapman.enqueueImageWrite(new Runnable() { + public void run() { + doFileWrites(fname, mtile, img, zmtile, zoomFile); + } }); return !isempty; } private void doFileWrites(final File fname, final KzedMapTile mtile, - final BufferedImage img, final KzedZoomedMapTile zmtile, final File zoomFile) { - Debug.debug("saving image " + fname.getPath()); - try { - ImageIO.write(img, "png", fname); - } catch (IOException e) { - Debug.error("Failed to save image: " + fname.getPath(), e); - } catch (java.lang.NullPointerException e) { - Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e); - } - mtile.file = fname; - // Since we've already got the new tile, and we're on an async thread, just - // make the zoomed tile here - int px = mtile.px; - int py = mtile.py; - int zpx = zmtile.getTileX(); - int zpy = zmtile.getTileY(); + final BufferedImage img, final KzedZoomedMapTile zmtile, final File zoomFile) { + Debug.debug("saving image " + fname.getPath()); + try { + ImageIO.write(img, "png", fname); + } catch (IOException e) { + Debug.error("Failed to save image: " + fname.getPath(), e); + } catch (java.lang.NullPointerException e) { + Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e); + } + mtile.file = fname; + // Since we've already got the new tile, and we're on an async thread, just + // make the zoomed tile here + int px = mtile.px; + int py = mtile.py; + int zpx = zmtile.getTileX(); + int zpy = zmtile.getTileY(); - /* scaled size */ - int scw = KzedMap.tileWidth / 2; - int sch = KzedMap.tileHeight / 2; + /* scaled size */ + int scw = KzedMap.tileWidth / 2; + int sch = KzedMap.tileHeight / 2; - /* origin in zoomed-out tile */ - int ox = 0; - int oy = 0; + /* origin in zoomed-out tile */ + int ox = 0; + int oy = 0; - if (zpx != px) - ox = scw; - if (zpy != py) - oy = sch; + if (zpx != px) + ox = scw; + if (zpy != py) + oy = sch; - BufferedImage zIm = null; - try { - zIm = ImageIO.read(zoomFile); - } catch (IOException e) { - } catch (IndexOutOfBoundsException e) { - } + BufferedImage zIm = null; + try { + zIm = ImageIO.read(zoomFile); + } catch (IOException e) { + } catch (IndexOutOfBoundsException e) { + } - if (zIm == null) { - /* create new one */ - zIm = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); - Debug.debug("New zoom-out tile created " + zmtile.getFilename()); - } else { - Debug.debug("Loaded zoom-out tile from " + zmtile.getFilename()); - } - - /* blit scaled rendered tile onto zoom-out tile */ - Graphics2D g2 = zIm.createGraphics(); - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g2.drawImage(img, ox, oy, scw, sch, null); + if (zIm == null) { + /* create new one */ + zIm = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); + Debug.debug("New zoom-out tile created " + zmtile.getFilename()); + } else { + Debug.debug("Loaded zoom-out tile from " + zmtile.getFilename()); + } + + /* blit scaled rendered tile onto zoom-out tile */ + Graphics2D g2 = zIm.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(img, ox, oy, scw, sch, null); - img.flush(); + img.flush(); - /* save zoom-out tile */ - - try { - ImageIO.write(zIm, "png", zoomFile); - Debug.debug("Saved zoom-out tile at " + zoomFile.getName()); - } catch (IOException e) { - Debug.error("Failed to save zoom-out tile: " + zoomFile.getName(), e); - } catch (java.lang.NullPointerException e) { - Debug.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e); - } - zIm.flush(); - /* Push updates for both files.*/ - MapManager.mapman.pushUpdate(mtile.getWorld(), - new Client.Tile(mtile.getFilename())); - MapManager.mapman.pushUpdate(zmtile.getWorld(), - new Client.Tile(zmtile.getFilename())); + /* save zoom-out tile */ + + try { + ImageIO.write(zIm, "png", zoomFile); + Debug.debug("Saved zoom-out tile at " + zoomFile.getName()); + } catch (IOException e) { + Debug.error("Failed to save zoom-out tile: " + zoomFile.getName(), e); + } catch (java.lang.NullPointerException e) { + Debug.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e); + } + zIm.flush(); + /* Push updates for both files.*/ + MapManager.mapman.pushUpdate(mtile.getWorld(), + new Client.Tile(mtile.getFilename())); + MapManager.mapman.pushUpdate(zmtile.getWorld(), + new Client.Tile(zmtile.getFilename())); } - protected Color scan(World world, int x, int y, int z, int seq) { + protected Color scan(World world, int x, int y, int z, int seq, boolean isnether) { + Color result = translucent; for (;;) { - if (y < 0) - return translucent; - + if (y < 0) { + return result; + } int id = world.getBlockTypeIdAt(x, y, z); byte data = 0; - if(colorScheme.datacolors[id] != null) { /* If data colored */ - data = world.getBlockAt(x, y, z).getData(); + if(isnether) { /* Make bedrock ceiling into air in nether */ + if(id != 0) { + /* Remember first color we see, in case we wind up solid */ + if(result == translucent) + if(colorScheme.colors[id] != null) + result = colorScheme.colors[id][seq]; + id = 0; + } + else + isnether = false; + } + if(colorScheme.datacolors[id] != null) { /* If data colored */ + data = world.getBlockAt(x, y, z).getData(); } switch (seq) { case 0: @@ -250,9 +250,9 @@ public class DefaultTileRenderer implements MapTileRenderer { } Color[] colors; if(data != 0) - colors = colorScheme.datacolors[id][data]; + colors = colorScheme.datacolors[id][data]; else - colors = colorScheme.colors[id]; + colors = colorScheme.colors[id]; if (colors != null) { Color c = colors[seq]; if (c.getAlpha() > 0) { @@ -263,7 +263,7 @@ public class DefaultTileRenderer implements MapTileRenderer { } /* this block is transparent, so recurse */ - Color bg = scan(world, x, y, z, seq); + Color bg = scan(world, x, y, z, seq, isnether); int cr = c.getRed(); int cg = c.getGreen(); diff --git a/src/main/java/org/dynmap/kzedmap/HighlightTileRenderer.java b/src/main/java/org/dynmap/kzedmap/HighlightTileRenderer.java index dd639b70..c0541289 100644 --- a/src/main/java/org/dynmap/kzedmap/HighlightTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/HighlightTileRenderer.java @@ -21,19 +21,31 @@ public class HighlightTileRenderer extends DefaultTileRenderer { highlightBlocks.add((Integer)highlightObj); } } - + @Override - protected Color scan(World world, int x, int y, int z, int seq) { + protected Color scan(World world, int x, int y, int z, int seq, boolean isnether) { Color result = translucent; + int top_nether_id = 0; for (;;) { if (y < 0) { break; } int id = world.getBlockTypeIdAt(x, y, z); + if(isnether) { /* Make bedrock ceiling into air in nether */ + if(id != 0) { + /* Remember first color we see, in case we wind up solid */ + if(result == translucent) + if(colorScheme.colors[id] != null) + result = colorScheme.colors[id][seq]; + id = 0; + } + else + isnether = false; + } byte data = 0; - if(colorScheme.datacolors[id] != null) { /* If data colored */ - data = world.getBlockAt(x, y, z).getData(); + if(colorScheme.datacolors[id] != null) { /* If data colored */ + data = world.getBlockAt(x, y, z).getData(); } switch (seq) { @@ -56,9 +68,9 @@ public class HighlightTileRenderer extends DefaultTileRenderer { if (id != 0) { Color[] colors; if(data != 0) - colors = colorScheme.datacolors[id][data]; + colors = colorScheme.datacolors[id][data]; else - colors = colorScheme.colors[id]; + colors = colorScheme.colors[id]; if (colors != null) { Color c = colors[seq]; diff --git a/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java b/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java index 4d5dee8d..a0de1520 100644 --- a/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java @@ -1,18 +1,8 @@ package org.dynmap.kzedmap; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; import java.io.File; -import java.io.IOException; import java.util.Map; -import javax.imageio.ImageIO; - -import org.dynmap.Client; -import org.dynmap.MapManager; -import org.dynmap.debug.Debug; - public class ZoomedTileRenderer { public ZoomedTileRenderer(Map configuration) { } diff --git a/web/js/map.js b/web/js/map.js index 0ae78f17..fdd69d2b 100644 --- a/web/js/map.js +++ b/web/js/map.js @@ -386,7 +386,7 @@ DynMap.prototype = { swtch(update.type, { tile: function() { - me.onTileUpdated(update.name); + me.onTileUpdated(update.name,update.timestamp); }, playerjoin: function() { $(me).trigger('playerjoin', [ update.playerName ]); @@ -436,12 +436,12 @@ DynMap.prototype = { unregisterTile: function(mapType, tileName) { delete this.registeredTiles[tileName]; }, - onTileUpdated: function(tileName) { + onTileUpdated: function(tileName,timestamp) { var me = this; var tile = this.registeredTiles[tileName]; if (tile) { - tile.lastseen = this.lasttimestamp; + tile.lastseen = timestamp; tile.mapType.onTileUpdated(tile.tileElement, tileName); } },