From 544283a650afc58ec6dd84e13e6d5b4700197446 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sun, 29 May 2011 09:33:51 -0500 Subject: [PATCH 1/2] More memory tuning on BufferedImage handling, workaround bukkit leak --- src/main/java/org/dynmap/MapChunkCache.java | 15 +++++++++++++++ src/main/java/org/dynmap/kzedmap/KzedMap.java | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dynmap/MapChunkCache.java b/src/main/java/org/dynmap/MapChunkCache.java index 636d2f48..e8d11145 100644 --- a/src/main/java/org/dynmap/MapChunkCache.java +++ b/src/main/java/org/dynmap/MapChunkCache.java @@ -14,6 +14,7 @@ public class MapChunkCache { private World w; private static Method getchunkdata = null; private static Method gethandle = null; + private static Method poppreservedchunk = null; private static Field heightmap = null; private static boolean initialized = false; @@ -177,6 +178,13 @@ public class MapChunkCache { } catch (NoSuchMethodException nsmx) { } catch (NoSuchFieldException nsfx) { } + /* Get CraftWorld.popPreservedChunk(x,z) - reduces memory bloat from map traversals (optional) */ + try { + Class c = Class.forName("org.bukkit.craftbukkit.CraftWorld"); + poppreservedchunk = c.getDeclaredMethod("popPreservedChunk", new Class[] { int.class, int.class }); + } catch (ClassNotFoundException cnfx) { + } catch (NoSuchMethodException nsmx) { + } initialized = true; if(gethandle != null) Log.info("Chunk snapshot support enabled"); @@ -220,6 +228,13 @@ public class MapChunkCache { * while the actual in-use chunk area for a player where the chunks are managed * by the MC base server is 21x21 (or about a 160 block radius) */ w.unloadChunk(chunk.x, chunk.z, false, false); + /* And pop preserved chunk - this is a bad leak in Bukkit for map traversals like us */ + try { + if(poppreservedchunk != null) + poppreservedchunk.invoke(w, chunk.x, chunk.z); + } catch (Exception x) { + Log.severe("Cannot pop preserved chunk - " + x.toString()); + } } } } diff --git a/src/main/java/org/dynmap/kzedmap/KzedMap.java b/src/main/java/org/dynmap/kzedmap/KzedMap.java index 6c4faa94..b456ae08 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMap.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMap.java @@ -293,8 +293,8 @@ public class KzedMap extends MapType { img.width = x; img.height = y; img.argb_buf = new int[x*y]; - img.buf_img = createBufferedImage(img.argb_buf, img.width, img.height); } + img.buf_img = createBufferedImage(img.argb_buf, img.width, img.height); return img; } @@ -303,6 +303,7 @@ public class KzedMap extends MapType { */ public static void freeBufferedImage(KzedBufferedImage img) { img.buf_img.flush(); + img.buf_img = null; /* Toss bufferedimage - seems to hold on to other memory */ synchronized(lock) { long k = (img.width<<16) + img.height; LinkedList ll = imgcache.get(k); From c00bd077cb1ea0262cee00414ad19b446b5887bf Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sun, 29 May 2011 17:24:46 -0500 Subject: [PATCH 2/2] Add support in web UI for automatic day/night cycle when night-and-day set for a given map. --- src/main/java/org/dynmap/Client.java | 10 ++++++++++ src/main/java/org/dynmap/DynmapWorld.java | 1 + src/main/java/org/dynmap/MapManager.java | 19 ++++++++++++++++++ src/main/java/org/dynmap/flat/FlatMap.java | 1 + .../dynmap/kzedmap/DefaultTileRenderer.java | 2 ++ web/js/flatmap.js | 7 +++++-- web/js/kzedmaps.js | 10 +++++++--- web/js/map.js | 20 ++++++++++++++++++- 8 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/dynmap/Client.java b/src/main/java/org/dynmap/Client.java index 03e7df03..dbf882fc 100644 --- a/src/main/java/org/dynmap/Client.java +++ b/src/main/java/org/dynmap/Client.java @@ -67,4 +67,14 @@ public class Client { this.name = name; } } + + public static class DayNight extends Update { + public String type = "daynight"; + public boolean isday; + + public DayNight(boolean isday) { + this.isday = isday; + } + } + } diff --git a/src/main/java/org/dynmap/DynmapWorld.java b/src/main/java/org/dynmap/DynmapWorld.java index e40fdc8d..170792d5 100644 --- a/src/main/java/org/dynmap/DynmapWorld.java +++ b/src/main/java/org/dynmap/DynmapWorld.java @@ -12,4 +12,5 @@ public class DynmapWorld { public UpdateQueue updates = new UpdateQueue(); public ConfigurationNode configuration; public List seedloc; + public int servertime; } diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 782444d9..b26c8261 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -162,6 +162,21 @@ public class MapManager { } } + private class CheckWorldTimes implements Runnable { + public void run() { + for(DynmapWorld w : worlds) { + int new_servertime = (int)(w.world.getTime() % 24000); + /* Check if we went from night to day */ + boolean wasday = w.servertime >= 0 && w.servertime < 13700; + boolean isday = new_servertime >= 0 && new_servertime < 13700; + w.servertime = new_servertime; + if(wasday != isday) { + MapManager.mapman.pushUpdate(w.world, new Client.DayNight(isday)); + } + } + } + } + public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) { plug_in = plugin; mapman = this; @@ -183,6 +198,9 @@ public class MapManager { for (World world : plug_in.getServer().getWorlds()) { activateWorld(world); } + + scheduler.scheduleSyncRepeatingTask(plugin, new CheckWorldTimes(), 5*20, 5*20); /* Check very 5 seconds */ + } void renderFullWorld(Location l) { @@ -234,6 +252,7 @@ public class MapManager { List loclist = worldConfiguration.getNodes("fullrenderlocations"); dynmapWorld.seedloc = new ArrayList(); + dynmapWorld.servertime = (int)(w.getTime() % 24000); if(loclist != null) { for(ConfigurationNode loc : loclist) { Location lx = new Location(w, loc.getDouble("x", 0), loc.getDouble("y", 64), loc.getDouble("z", 0)); diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index d16861ca..8dfb777a 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -292,6 +292,7 @@ public class FlatMap extends MapType { s(o, "title", c.getString("title")); s(o, "icon", c.getString("icon")); s(o, "prefix", c.getString("prefix")); + s(o, "nightandday", c.getBoolean("night-and-day",false)); a(worldObject, "maps", o); } } diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index cf7a5813..7b5b72a1 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -360,6 +360,8 @@ public class DefaultTileRenderer implements MapTileRenderer { int lightlevel = 15; int lightlevel_day = 15; result.setTransparent(); + if(result_day != null) + result_day.setTransparent(); for (;;) { if (mapiter.y < 0) { return; diff --git a/web/js/flatmap.js b/web/js/flatmap.js index 8035a94e..88a7429d 100644 --- a/web/js/flatmap.js +++ b/web/js/flatmap.js @@ -25,8 +25,11 @@ FlatMapType.prototype = $.extend(new DynMapType(), { var imgSize; var tileName; - tileName = this.prefix + '_128_' + coord.x + '_' + coord.y + '.png'; - + var dnprefix = ''; + if(this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].nightandday && this.dynmap.serverday) + dnprefix = '_day'; + + tileName = this.prefix + dnprefix + '_128_' + coord.x + '_' + coord.y + '.png'; imgSize = Math.pow(2, 7+zoom); var tile = $('
') .addClass('tile') diff --git a/web/js/kzedmaps.js b/web/js/kzedmaps.js index 825023e2..239efafa 100644 --- a/web/js/kzedmaps.js +++ b/web/js/kzedmaps.js @@ -42,18 +42,22 @@ KzedMapType.prototype = $.extend(new DynMapType(), { var debugred; var debugblue; - + + var dnprefix = ''; + if(this.dynmap.map.mapTypes[this.dynmap.map.mapTypeId].nightandday && this.dynmap.serverday) + dnprefix = '_day'; + if (zoom == 0) { // Most zoomed out tiles. tileSize = 128; imgSize = tileSize; - tileName = 'z' + this.prefix + '_' + (-coord.x * tileSize*2) + '_' + (coord.y * tileSize*2) + '.png'; + tileName = 'z' + this.prefix + dnprefix + '_' + (-coord.x * tileSize*2) + '_' + (coord.y * tileSize*2) + '.png'; } else { // Other zoom levels. tileSize = 128; imgSize = Math.pow(2, 6+zoom); - tileName = this.prefix + '_' + (-coord.x*tileSize) + '_' + (coord.y*tileSize) + '.png'; + tileName = this.prefix + dnprefix + '_' + (-coord.x*tileSize) + '_' + (coord.y*tileSize) + '.png'; } var img; var tile = $('
') diff --git a/web/js/map.js b/web/js/map.js index 539b80be..114bb19a 100644 --- a/web/js/map.js +++ b/web/js/map.js @@ -91,6 +91,8 @@ DynMap.prototype = { registeredTiles: [], players: {}, lasttimestamp: '0', + servertime: 0, + serverday: false, followingPlayer: '', formatUrl: function(name, options) { var url = this.options.url[name]; @@ -369,7 +371,23 @@ DynMap.prototype = { if (!me.options.jsonfile) { me.lasttimestamp = update.timestamp; } - + + me.servertime = update.servertime; + var oldday = me.serverday; + if(me.servertime > 23100 || me.servertime < 12900) + me.serverday = true; + else + me.serverday = false; + if(me.serverday != oldday) { + var mtid = me.map.mapTypeId; + if(me.map.mapTypes[mtid].nightandday) { + me.map.setMapTypeId('none'); + window.setTimeout(function() { + me.map.setMapTypeId(mtid); + }, 1); + } + } + var newplayers = {}; $.each(update.players, function(index, playerUpdate) { var name = playerUpdate.name;