diff --git a/configuration.txt b/configuration.txt index 5401e0a1..5f335235 100644 --- a/configuration.txt +++ b/configuration.txt @@ -73,6 +73,9 @@ display-whitelist: false # How often a tile gets rendered (in seconds). renderinterval: 1 +# Zoom-out tile update period - how often to scan for and process tile updates into zoom-out tiles (in seconds) +zoomoutperiod: 60 + # Tile hashing is used to minimize tile file updates when no changes have occurred - set to false to disable enabletilehash: true @@ -133,6 +136,8 @@ templates: enabled: true # # If bigworld set to true, use alternate directory layout better suited to large worlds # bigworld: true + # # Number of extra zoom-out levels for world (each level is twice as big as the previous one) + # extrazoomout: 3 center: x: 0 y: 64 @@ -209,6 +214,8 @@ templates: enabled: true # # If bigworld set to true, use alternate directory layout better suited to large worlds # bigworld: true + # # Number of extra zoom-out levels for world (each level is twice as big as the previous one) + # extrazoomout: 3 center: x: 0 y: 64 @@ -238,6 +245,8 @@ templates: enabled: true # # If bigworld set to true, use alternate directory layout better suited to large worlds # bigworld: true + # # Number of extra zoom-out levels for world (each level is twice as big as the previous one) + # extrazoomout: 3 center: x: 0 y: 64 @@ -312,6 +321,8 @@ worlds: # z: 0 # # If bigworld set to true, use alternate directory layout better suited to large worlds # bigworld: true + # # Number of extra zoom-out levels for world (each level is twice as big as the previous one) + # extrazoomout: 3 # maps: # - class: org.dynmap.flat.FlatMap # name: flat @@ -381,6 +392,8 @@ worlds: # x: 0 # y: 64 # z: 0 + # # Number of extra zoom-out levels for world (each level is twice as big as the previous one) + # extrazoomout: 3 # maps: # - class: org.dynmap.flat.FlatMap # name: flat diff --git a/src/main/java/org/dynmap/DynmapWorld.java b/src/main/java/org/dynmap/DynmapWorld.java index 708b9e4c..4afb3fc9 100644 --- a/src/main/java/org/dynmap/DynmapWorld.java +++ b/src/main/java/org/dynmap/DynmapWorld.java @@ -1,7 +1,6 @@ package org.dynmap; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import org.bukkit.World; @@ -62,18 +61,25 @@ public class DynmapWorld { } } + private static class PrefixData { + int stepsize; + int[] stepseq; + } + public void freshenZoomOutFilesByLevel(File tilepath, int zoomlevel) { - Log.info("freshenZoomOutFiles(" + tilepath.getPath() + "," + zoomlevel + ")"); + Debug.debug("freshenZoomOutFiles(" + tilepath.getPath() + "," + zoomlevel + ")"); File worldpath = new File(tilepath, world.getName()); /* Make path to our world */ if(worldpath.exists() == false) /* Quit if not found */ return; - HashMap maptab = new HashMap(); + HashMap maptab = new HashMap(); /* Build table of file prefixes and step sizes */ for(MapType mt : maps) { + PrefixData pd = new PrefixData(); List pfx = mt.baseZoomFilePrefixes(); - Integer step = mt.baseZoomFileStepSize(); + pd.stepsize = mt.baseZoomFileStepSize(); + pd.stepseq = mt.zoomFileStepSequence(); for(String p : pfx) { - maptab.put(p, step); + maptab.put(p, pd); } } if(bigworld) { /* If big world, next directories are map name specific */ @@ -103,10 +109,10 @@ public class DynmapWorld { private static class ProcessTileRec { File zf; - int x, z; + int x, y; } - private void processZoomDirectory(File dir, int stepsize, String prefix, int zoomlevel) { - Log.info("processZoomDirectory(" + dir.getPath() + "," + stepsize + "," + prefix + "," + zoomlevel + ")"); + private void processZoomDirectory(File dir, PrefixData pd, String prefix, int zoomlevel) { + Debug.debug("processZoomDirectory(" + dir.getPath() + "," + pd.stepsize + "," + prefix + "," + zoomlevel + ")"); String zoomprefix = "zzzzzzzzzzzzzzzzzzzz".substring(0, zoomlevel); HashMap toprocess = new HashMap(); if(prefix.equals("")) { @@ -124,12 +130,12 @@ public class DynmapWorld { fn = fn.substring(0, fn.lastIndexOf('.')); /* Strip off extension */ String[] tok = fn.split("_"); /* Split by underscores */ int x = 0; - int z = 0; + int y = 0; boolean parsed = false; if(tok.length >= 2) { try { x = Integer.parseInt(tok[tok.length-2]); - z = Integer.parseInt(tok[tok.length-1]); + y = Integer.parseInt(tok[tok.length-1]); parsed = true; } catch (NumberFormatException nfx) { } @@ -137,18 +143,18 @@ public class DynmapWorld { if(!parsed) continue; if(x >= 0) - x = x - (x % (stepsize << zoomlevel)); + x = x - (x % (pd.stepsize << zoomlevel)); else - x = x + (x % (stepsize << zoomlevel)); - if(z >= 0) - z = z - (z % (stepsize << zoomlevel)); + x = x + (x % (pd.stepsize << zoomlevel)); + if(y >= 0) + y = y - (y % (pd.stepsize << zoomlevel)); else - z = z + (z % (stepsize << zoomlevel)); + y = y + (y % (pd.stepsize << zoomlevel)); File zf; if(prefix.equals("")) - zf = new File(dir, "z_" + x + "_" + z + ".png"); + zf = new File(dir, "z_" + x + "_" + y + ".png"); else - zf = new File(dir, "z" + prefix + x + "_" + z + ".png"); + zf = new File(dir, "z" + prefix + x + "_" + y + ".png"); /* If zoom file exists and is older than our file, nothing to do */ if(zf.exists() && (zf.lastModified() >= f.lastModified())) { continue; @@ -158,17 +164,17 @@ public class DynmapWorld { ProcessTileRec rec = new ProcessTileRec(); rec.zf = zf; rec.x = x; - rec.z = z; + rec.y = y; toprocess.put(zfpath, rec); } } /* Do processing */ for(ProcessTileRec s : toprocess.values()) { - processZoomTile(dir, s.zf, s.x, s.z, stepsize << (zoomlevel-1), prefix); + processZoomTile(dir, s.zf, s.x, s.y, pd.stepsize << (zoomlevel-1), prefix, pd.stepseq); } } - private void processZoomTile(File dir, File zf, int tx, int tz, int stepsize, String prefix) { - Log.info("processZoomFile(" + dir.getPath() + "," + zf.getPath() + "," + tx + "," + tz + "," + stepsize + "," + prefix); + private void processZoomTile(File dir, File zf, int tx, int ty, int stepsize, String prefix, int[] stepseq) { + Debug.debug("processZoomFile(" + dir.getPath() + "," + zf.getPath() + "," + tx + "," + ty + "," + stepsize + "," + prefix); int width = 128, height = 128; BufferedImage zIm = null; KzedBufferedImage kzIm = null; @@ -179,14 +185,16 @@ public class DynmapWorld { zIm = kzIm.buf_img; for(int i = 0; i < 4; i++) { - File f = new File(dir, prefix + (tx + stepsize*(i>>1)) + "_" + (tz + stepsize*(i&1)) + ".png"); + File f = new File(dir, prefix + (tx + stepsize*(1&stepseq[i])) + "_" + (ty + stepsize*(stepseq[i]>>1)) + ".png"); if(f.exists()) { BufferedImage im = null; + FileLockManager.getReadLock(f); try { im = ImageIO.read(f); } catch (IOException e) { } catch (IndexOutOfBoundsException e) { } + FileLockManager.releaseReadLock(f); if(im != null) { im.getRGB(0, 0, width, height, argb, 0, width); /* Read data */ im.flush(); @@ -216,6 +224,7 @@ public class DynmapWorld { } } } + FileLockManager.getWriteLock(zf); try { FileLockManager.imageIOWrite(zIm, "png", zf); Debug.debug("Saved zoom-out tile at " + zf.getName()); @@ -224,6 +233,7 @@ public class DynmapWorld { } catch (java.lang.NullPointerException e) { Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e); } + FileLockManager.releaseWriteLock(zf); KzedMap.freeBufferedImage(kzIm); } } diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 2036e25b..ce149601 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -26,13 +26,15 @@ public class MapManager { public AsynchronousQueue tileQueue; private static final int DEFAULT_CHUNKS_PER_TICK = 200; - + private static final int DEFAULT_ZOOMOUT_PERIOD = 60; public List worlds = new ArrayList(); public Map worldsLookup = new HashMap(); private BukkitScheduler scheduler; private DynmapPlugin plug_in; private long timeslice_int = 0; /* In milliseconds */ private int max_chunk_loads_per_tick = DEFAULT_CHUNKS_PER_TICK; + + private int zoomout_period = DEFAULT_ZOOMOUT_PERIOD; /* Zoom-out tile processing period, in seconds */ /* Which fullrenders are active */ private HashMap active_renders = new HashMap(); /* List of MapChunkCache requests to be processed */ @@ -263,12 +265,12 @@ public class MapManager { private class DoZoomOutProcessing implements Runnable { public void run() { - Log.info("DoZoomOutProcessing started"); + Debug.debug("DoZoomOutProcessing started"); for(DynmapWorld w : worlds) { - w.freshenZoomOutFiles(plug_in.tilesDirectory); + w.freshenZoomOutFiles(DynmapPlugin.tilesDirectory); } - renderpool.schedule(this, 60000, TimeUnit.MILLISECONDS); - Log.info("DoZoomOutProcessing finished"); + renderpool.schedule(this, zoomout_period, TimeUnit.SECONDS); + Debug.debug("DoZoomOutProcessing finished"); } } @@ -287,6 +289,10 @@ public class MapManager { timeslice_int = (long)(configuration.getDouble("timesliceinterval", 0.0) * 1000); max_chunk_loads_per_tick = configuration.getInteger("maxchunkspertick", DEFAULT_CHUNKS_PER_TICK); if(max_chunk_loads_per_tick < 5) max_chunk_loads_per_tick = 5; + /* Get zoomout processing periond in seconds */ + zoomout_period = configuration.getInteger("zoomoutperiod", DEFAULT_ZOOMOUT_PERIOD); + if(zoomout_period < 5) zoomout_period = 5; + scheduler = plugin.getServer().getScheduler(); hashman = new TileHashManager(DynmapPlugin.tilesDirectory, configuration.getBoolean("enabletilehash", true)); diff --git a/src/main/java/org/dynmap/MapType.java b/src/main/java/org/dynmap/MapType.java index f8cff80f..b0e92bbf 100644 --- a/src/main/java/org/dynmap/MapType.java +++ b/src/main/java/org/dynmap/MapType.java @@ -30,11 +30,9 @@ public abstract class MapType { public abstract List baseZoomFilePrefixes(); public abstract int baseZoomFileStepSize(); - public enum ZoomStepDirection { - POSITIVE_X_Y, - NEGATIVE_X_Y, - POSITIVE_X_NEGATIVE_Y, - NEGATIVE_X_POSITIVE_Y - } - public abstract ZoomStepDirection zoomFileStepDirection(); + /** + * Step sequence for creating zoomed file: first index is top-left, second top-right, third bottom-left, forth bottom-right + * Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3) + */ + public abstract int[] zoomFileStepSequence(); } diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index 980c916b..78e828e6 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -22,10 +22,8 @@ import org.dynmap.MapManager; import org.dynmap.TileHashManager; import org.dynmap.MapTile; import org.dynmap.MapType; -import org.dynmap.MapType.ZoomStepDirection; import org.dynmap.debug.Debug; import org.dynmap.kzedmap.KzedMap; -import org.dynmap.kzedmap.MapTileRenderer; import org.dynmap.kzedmap.KzedMap.KzedBufferedImage; import org.dynmap.utils.FileLockManager; import org.dynmap.utils.MapChunkCache; @@ -418,7 +416,9 @@ public class FlatMap extends MapType { public int baseZoomFileStepSize() { return 1; } - public ZoomStepDirection zoomFileStepDirection() { return ZoomStepDirection.POSITIVE_X_Y; } + private static final int[] stepseq = { 1, 3, 0, 2 }; + + public int[] zoomFileStepSequence() { return stepseq; } public static class FlatMapTile extends MapTile { FlatMap map; diff --git a/src/main/java/org/dynmap/kzedmap/KzedMap.java b/src/main/java/org/dynmap/kzedmap/KzedMap.java index d13aa2bd..4e12f3bf 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMap.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMap.java @@ -17,7 +17,6 @@ import org.dynmap.Log; import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; -import org.dynmap.MapType.ZoomStepDirection; import org.dynmap.utils.MapChunkCache; import org.json.simple.JSONObject; import java.awt.image.DataBufferInt; @@ -339,7 +338,9 @@ public class KzedMap extends MapType { public int baseZoomFileStepSize() { return zTileWidth; } - public ZoomStepDirection zoomFileStepDirection() { return ZoomStepDirection.NEGATIVE_X_POSITIVE_Y; } + private static final int[] stepseq = { 0, 2, 1, 3 }; + + public int[] zoomFileStepSequence() { return stepseq; } public String getName() { return "KzedMap"; diff --git a/src/main/java/org/dynmap/regions/RegionHandler.java b/src/main/java/org/dynmap/regions/RegionHandler.java index 48aa9616..01ecd248 100644 --- a/src/main/java/org/dynmap/regions/RegionHandler.java +++ b/src/main/java/org/dynmap/regions/RegionHandler.java @@ -72,10 +72,7 @@ public class RegionHandler extends FileHandler { /* If not in list, remove it */ if(!idlist.contains(id)) { regionData.remove(id); - log.info("discard " + id); } - else - log.info("keep " + id); } } try {