diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 5acd0009..94efd05f 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -371,7 +371,17 @@ public class MapManager { else sendMessage(String.format("%s of map '%s' of '%s' completed - %d tiles rendered (%.2f msec/map-tile, %.2f msec per render)", rendertype, activemaps, world.world.getName(), rendercnt, msecpertile, rendtime)); - + /* Now, if fullrender, use the render bitmap to purge obsolete tiles */ + if(cxmin == Integer.MIN_VALUE) { + if(activemapcnt == 1) { + map.purgeOldTiles(world, rendered); + } + else { + for(MapType mt : map.getMapsSharingRender(world)) { + mt.purgeOldTiles(world, rendered); + } + } + } } found.clear(); rendered.clear(); @@ -566,11 +576,9 @@ public class MapManager { total_render_ns.addAndGet(System.nanoTime()-rt0); rendercalls.incrementAndGet(); synchronized(lock) { -// found.setFlag(tile.tileOrdinalX(),tile.tileOrdinalY(),false); rendered.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), true); for (MapTile adjTile : map.getAdjecentTiles(tile)) { - if (!found.getFlag(adjTile.tileOrdinalX(),adjTile.tileOrdinalY()) && - !rendered.getFlag(adjTile.tileOrdinalX(),adjTile.tileOrdinalY())) { + if (!found.getFlag(adjTile.tileOrdinalX(),adjTile.tileOrdinalY())) { found.setFlag(adjTile.tileOrdinalX(), adjTile.tileOrdinalY(), true); renderQueue.add(adjTile); } @@ -578,7 +586,6 @@ public class MapManager { } } synchronized(lock) { -// found.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), false); if(!cache.isEmpty()) { rendercnt++; timeaccum += System.currentTimeMillis() - tstart; @@ -1173,11 +1180,9 @@ public class MapManager { /** * Update map tile statistics */ - public void updateStatistics(MapTile tile, String subtype, boolean rendered, boolean updated, boolean transparent) { + public void updateStatistics(MapTile tile, String prefix, boolean rendered, boolean updated, boolean transparent) { synchronized(lock) { - String k = tile.getKey(); - if(subtype != null) - k += "." + subtype; + String k = tile.getKey(prefix); MapStats ms = mapstats.get(k); if(ms == null) { ms = new MapStats(); diff --git a/src/main/java/org/dynmap/MapTile.java b/src/main/java/org/dynmap/MapTile.java index 1d67ae40..2c5a2f1c 100644 --- a/src/main/java/org/dynmap/MapTile.java +++ b/src/main/java/org/dynmap/MapTile.java @@ -40,7 +40,7 @@ public abstract class MapTile { @Override public abstract boolean equals(Object obj); - public abstract String getKey(); + public abstract String getKey(String prefix); public abstract boolean isBiomeDataNeeded(); public abstract boolean isHightestBlockYDataNeeded(); diff --git a/src/main/java/org/dynmap/MapType.java b/src/main/java/org/dynmap/MapType.java index adb649e3..1a4f9eb4 100644 --- a/src/main/java/org/dynmap/MapType.java +++ b/src/main/java/org/dynmap/MapType.java @@ -1,8 +1,11 @@ package org.dynmap; +import java.io.File; +import java.util.LinkedList; import java.util.List; import org.bukkit.Location; +import org.dynmap.utils.TileFlags; import org.json.simple.JSONObject; public abstract class MapType { @@ -80,5 +83,31 @@ public abstract class MapType { * Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3) */ public abstract int[] zoomFileStepSequence(); + + public void purgeOldTiles(DynmapWorld world, TileFlags rendered) { } + + public interface FileCallback { + public void fileFound(File f, File parent, boolean day); + } + protected void walkMapTree(File root, FileCallback cb, boolean day) { + LinkedList dirs = new LinkedList(); + String ext = "." + getImageFormat().getFileExt(); + dirs.add(root); + while(dirs.isEmpty() == false) { + File dir = dirs.pop(); + String[] lst = dir.list(); + for(String fn : lst) { + if(fn.equals(".") || fn.equals("..")) + continue; + File f = new File(dir, fn); + if(f.isDirectory()) { /* If directory, add to list to process */ + dirs.add(f); + } + else if(fn.endsWith(ext)) { /* Else, if matches suffix */ + cb.fileFound(f, dir, day); + } + } + } + } } diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index 4573eef5..0b00ffda 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -303,7 +303,7 @@ public class FlatMap extends MapType { boolean tile_update = false; FileLockManager.getWriteLock(outputFile); try { - if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), null, t.x, t.y))) { + if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(prefix), null, t.x, t.y))) { /* Wrap buffer as buffered image */ Debug.debug("saving image " + outputFile.getPath()); if(!outputFile.getParentFile().exists()) @@ -316,7 +316,7 @@ public class FlatMap extends MapType { Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e); } MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename())); - hashman.updateHashCode(tile.getKey(), null, t.x, t.y, crc); + hashman.updateHashCode(tile.getKey(prefix), null, t.x, t.y, crc); tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile); tile_update = true; } @@ -327,7 +327,7 @@ public class FlatMap extends MapType { FileLockManager.releaseWriteLock(outputFile); DynmapBufferedImage.freeBufferedImage(im); } - MapManager.mapman.updateStatistics(tile, null, true, tile_update, !rendered); + MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, !rendered); /* If day too, handle it */ if(night_and_day) { @@ -335,7 +335,7 @@ public class FlatMap extends MapType { crc = hashman.calculateTileHash(argb_buf_day); FileLockManager.getWriteLock(dayfile); try { - if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), "day", t.x, t.y))) { + if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(prefix), "day", t.x, t.y))) { Debug.debug("saving image " + dayfile.getPath()); if(!dayfile.getParentFile().exists()) dayfile.getParentFile().mkdirs(); @@ -347,7 +347,7 @@ public class FlatMap extends MapType { Debug.error("Failed to save image (NullPointerException): " + dayfile.getPath(), e); } MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getDayFilename())); - hashman.updateHashCode(tile.getKey(), "day", t.x, t.y, crc); + hashman.updateHashCode(tile.getKey(prefix), "day", t.x, t.y, crc); tile.getDynmapWorld().enqueueZoomOutUpdate(dayfile); tile_update = true; } @@ -359,7 +359,7 @@ public class FlatMap extends MapType { FileLockManager.releaseWriteLock(dayfile); DynmapBufferedImage.freeBufferedImage(im_day); } - MapManager.mapman.updateStatistics(tile, "day", true, tile_update, !rendered); + MapManager.mapman.updateStatistics(tile, prefix+"_day", true, tile_update, !rendered); } return rendered; @@ -574,7 +574,7 @@ public class FlatMap extends MapType { } @Override - public String getKey() { + public String getKey(String prefix) { return world.world.getName() + "." + map.getPrefix(); } diff --git a/src/main/java/org/dynmap/hdmap/HDMap.java b/src/main/java/org/dynmap/hdmap/HDMap.java index a9b506a6..8439ce27 100644 --- a/src/main/java/org/dynmap/hdmap/HDMap.java +++ b/src/main/java/org/dynmap/hdmap/HDMap.java @@ -7,17 +7,23 @@ import java.io.File; import java.util.ArrayList; import java.util.List; import org.bukkit.Location; +import org.dynmap.Client; import org.dynmap.ConfigurationNode; import org.dynmap.DynmapChunk; +import org.dynmap.DynmapPlugin; import org.dynmap.DynmapWorld; import org.dynmap.Log; import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; +import org.dynmap.debug.Debug; import org.dynmap.kzedmap.MapTileRenderer; import org.dynmap.utils.MapChunkCache; +import org.dynmap.utils.TileFlags; import org.json.simple.JSONObject; +import com.avaje.ebean.text.StringParser; + public class HDMap extends MapType { private String name; @@ -270,4 +276,61 @@ public class HDMap extends MapType { public int getBackgroundARGBNight() { return bgcolornight; } + + private HDMapTile fileToTile(DynmapWorld world, File f) { + String n = f.getName(); + n = n.substring(0, n.lastIndexOf('.')); + if(n == null) return null; + String[] nt = n.split("_"); + if(nt.length != 2) return null; + int xx, zz; + try { + xx = Integer.parseInt(nt[0]); + zz = Integer.parseInt(nt[1]); + } catch (NumberFormatException nfx) { + return null; + } + return new HDMapTile(world, perspective, xx, zz); + } + + public void purgeOldTiles(final DynmapWorld world, final TileFlags rendered) { + File basedir = new File(world.worldtilepath, prefix); /* Get base directory for map */ + FileCallback cb = new FileCallback() { + public void fileFound(File f, File parent, boolean day) { + String n = f.getName(); + if(n.startsWith("z")) { /* If zoom file */ + if(n.startsWith("z_")) { /* First tier of zoom? */ + File ff = new File(parent, n.substring(2)); /* Make file for render tier, and drive update */ + HDMapTile tile = fileToTile(world, ff); /* Parse it */ + if(tile == null) return; + if(rendered.getFlag(tile.tx, tile.ty) || rendered.getFlag(tile.tx+1, tile.ty) || + rendered.getFlag(tile.tx, tile.ty-1) || rendered.getFlag(tile.tx+1, tile.ty-1)) + return; + world.enqueueZoomOutUpdate(ff); + } + return; + } + HDMapTile tile = fileToTile(world, f); + if(tile == null) return; + + if(rendered.getFlag(tile.tx, tile.ty)) { /* If we rendered this tile, its good */ + return; + } + Debug.debug("clean up " + f.getPath()); + /* Otherwise, delete tile */ + f.delete(); + /* Push updates, clear hash code, and signal zoom tile update */ + MapManager.mapman.pushUpdate(world.world, + new Client.Tile(day?tile.getDayFilename(prefix, getImageFormat()):tile.getFilename(prefix, getImageFormat()))); + MapManager.mapman.hashman.updateHashCode(tile.getKey(prefix), day?"day":null, tile.tx, tile.ty, -1); + world.enqueueZoomOutUpdate(f); + } + + }; + walkMapTree(basedir, cb, false); + if(lighting.isNightAndDayEnabled()) { + basedir = new File(world.worldtilepath, prefix+"_day"); + walkMapTree(basedir, cb, true); + } + } } diff --git a/src/main/java/org/dynmap/hdmap/HDMapTile.java b/src/main/java/org/dynmap/hdmap/HDMapTile.java index a03f536b..67938c04 100644 --- a/src/main/java/org/dynmap/hdmap/HDMapTile.java +++ b/src/main/java/org/dynmap/hdmap/HDMapTile.java @@ -73,8 +73,8 @@ public class HDMapTile extends MapTile { return o.tx == tx && o.ty == ty && (perspective == o.perspective) && (o.getWorld() == getWorld()); } - public String getKey() { - return getWorld().getName() + "." + perspective.getName(); + public String getKey(String prefix) { + return getWorld().getName() + "." + prefix; } @Override diff --git a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index 10c96fd3..c15b23f7 100644 --- a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -1186,7 +1186,7 @@ public class IsoHDPerspective implements HDPerspective { try { if(rendered[i]) renderone = true; - if((!f.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), prefix, tile.tx, tile.ty))) { + if((!f.exists()) || (crc != hashman.getImageHashCode(tile.getKey(prefix), null, tile.tx, tile.ty))) { /* Wrap buffer as buffered image */ Debug.debug("saving image " + f.getPath()); if(!f.getParentFile().exists()) @@ -1199,7 +1199,7 @@ public class IsoHDPerspective implements HDPerspective { Debug.error("Failed to save image (NullPointerException): " + f.getPath(), e); } MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(fname)); - hashman.updateHashCode(tile.getKey(), prefix, tile.tx, tile.ty, crc); + hashman.updateHashCode(tile.getKey(prefix), null, tile.tx, tile.ty, crc); tile.getDynmapWorld().enqueueZoomOutUpdate(f); tile_update = true; } @@ -1216,10 +1216,9 @@ public class IsoHDPerspective implements HDPerspective { fname = tile.getDayFilename(prefix, fmt); f = new File(tile.getDynmapWorld().worldtilepath, fname); FileLockManager.getWriteLock(f); - prefix = prefix+"_day"; tile_update = false; try { - if((!f.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), prefix, tile.tx, tile.ty))) { + if((!f.exists()) || (crc != hashman.getImageHashCode(tile.getKey(prefix), "day", tile.tx, tile.ty))) { /* Wrap buffer as buffered image */ Debug.debug("saving image " + f.getPath()); if(!f.getParentFile().exists()) @@ -1232,7 +1231,7 @@ public class IsoHDPerspective implements HDPerspective { Debug.error("Failed to save image (NullPointerException): " + f.getPath(), e); } MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(fname)); - hashman.updateHashCode(tile.getKey(), prefix, tile.tx, tile.ty, crc); + hashman.updateHashCode(tile.getKey(prefix), "day", tile.tx, tile.ty, crc); tile.getDynmapWorld().enqueueZoomOutUpdate(f); tile_update = true; } @@ -1243,7 +1242,7 @@ public class IsoHDPerspective implements HDPerspective { FileLockManager.releaseWriteLock(f); DynmapBufferedImage.freeBufferedImage(dayim[i]); } - MapManager.mapman.updateStatistics(tile, prefix, true, tile_update, !rendered[i]); + MapManager.mapman.updateStatistics(tile, prefix+"_day", true, tile_update, !rendered[i]); } } return renderone; diff --git a/src/main/java/org/dynmap/hdmap/TexturePack.java b/src/main/java/org/dynmap/hdmap/TexturePack.java index 1aea17a3..3d4cc35e 100644 --- a/src/main/java/org/dynmap/hdmap/TexturePack.java +++ b/src/main/java/org/dynmap/hdmap/TexturePack.java @@ -1048,7 +1048,7 @@ public class TexturePack { rslt.setTransparent(); return; } - /* If warer block, to watercolor tone op */ + /* If water block, to watercolor tone op */ if((blkid == 8) || (blkid == 9)) { textop = COLORMOD_WATERTONED; } diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index 0c3c161d..0f3ba68c 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -273,7 +273,7 @@ public class DefaultTileRenderer implements MapTileRenderer { int ty = mtile.py/KzedMap.tileHeight; FileLockManager.getWriteLock(fname); try { - if((!fname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), null, tx, ty))) { + if((!fname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(prefix), null, tx, ty))) { Debug.debug("saving image " + fname.getPath()); if(!fname.getParentFile().exists()) fname.getParentFile().mkdirs(); @@ -285,14 +285,14 @@ public class DefaultTileRenderer implements MapTileRenderer { Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e); } MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getFilename())); - hashman.updateHashCode(mtile.getKey(), null, tx, ty, crc); + hashman.updateHashCode(mtile.getKey(prefix), null, tx, ty, crc); updated_fname = true; } } finally { FileLockManager.releaseWriteLock(fname); DynmapBufferedImage.freeBufferedImage(img); } - MapManager.mapman.updateStatistics(mtile, null, true, updated_fname, !rendered); + MapManager.mapman.updateStatistics(mtile, prefix, true, updated_fname, !rendered); mtile.file = fname; @@ -303,7 +303,7 @@ public class DefaultTileRenderer implements MapTileRenderer { crc = hashman.calculateTileHash(img.argb_buf); FileLockManager.getWriteLock(dfname); try { - if((!dfname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), "day", tx, ty))) { + if((!dfname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(prefix), "day", tx, ty))) { Debug.debug("saving image " + dfname.getPath()); if(!dfname.getParentFile().exists()) dfname.getParentFile().mkdirs(); @@ -315,14 +315,14 @@ public class DefaultTileRenderer implements MapTileRenderer { Debug.error("Failed to save image (NullPointerException): " + dfname.getPath(), e); } MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getDayFilename())); - hashman.updateHashCode(mtile.getKey(), "day", tx, ty, crc); + hashman.updateHashCode(mtile.getKey(prefix), "day", tx, ty, crc); updated_dfname = true; } } finally { FileLockManager.releaseWriteLock(dfname); DynmapBufferedImage.freeBufferedImage(img_day); } - MapManager.mapman.updateStatistics(mtile, "day", true, updated_dfname, !rendered); + MapManager.mapman.updateStatistics(mtile, prefix+"_day", true, updated_dfname, !rendered); } // Since we've already got the new tile, and we're on an async thread, just diff --git a/src/main/java/org/dynmap/kzedmap/KzedMapTile.java b/src/main/java/org/dynmap/kzedmap/KzedMapTile.java index 8afabf29..552794fe 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMapTile.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMapTile.java @@ -98,8 +98,8 @@ public class KzedMapTile extends MapTile { return o.px == px && o.py == py && (o.map == map) && (o.getWorld() == getWorld()); } - public String getKey() { - return getWorld().getName() + "." + renderer.getPrefix(); + public String getKey(String prefix) { + return getWorld().getName() + "." + prefix; } public String toString() { diff --git a/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java b/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java index 63b401a0..fd2516cb 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java +++ b/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java @@ -85,8 +85,8 @@ public class KzedZoomedMapTile extends MapTile { } - public String getKey() { - return getWorld().getName() + ".z" + originalTile.renderer.getPrefix(); + public String getKey(String prefix) { + return getWorld().getName() + ".z" + prefix; } @Override