diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 03efe09a..be0693ce 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -1,6 +1,8 @@ package org.dynmap; import java.io.File; +import java.io.IOException; +import java.awt.image.BufferedImage; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; @@ -12,6 +14,8 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.HashMap; +import javax.imageio.ImageIO; +import org.dynmap.kzedmap.KzedMapTile; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; @@ -20,12 +24,15 @@ import org.bukkit.util.config.ConfigurationNode; import org.dynmap.DynmapWorld; import org.dynmap.MapTile; import org.dynmap.debug.Debug; +import org.dynmap.kzedmap.KzedMap; +import org.dynmap.kzedmap.KzedZoomedMapTile; import org.bukkit.Chunk; public class MapManager { protected static final Logger log = Logger.getLogger("Minecraft"); public AsynchronousQueue tileQueue; + public AsynchronousQueue writeQueue; public Map worlds = new HashMap(); public Map inactiveworlds = new HashMap(); @@ -40,6 +47,12 @@ public class MapManager { /* lock for our data structures */ public static final Object lock = new Object(); + public static MapManager mapman; /* Our singleton */ + + private static class ImageWriter { + Runnable run; + } + private class FullWorldRenderState implements Runnable { DynmapWorld world; /* Which world are we rendering */ Location loc; /* Start location */ @@ -146,6 +159,9 @@ public class MapManager { } public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) { + + mapman = this; + this.tileQueue = new AsynchronousQueue(new Handler() { @Override public void handle(MapTile t) { @@ -157,6 +173,14 @@ public class MapManager { } }, (int) (configuration.getDouble("renderinterval", 0.5) * 1000)); + this.writeQueue = new AsynchronousQueue( + new Handler() { + @Override + public void handle(ImageWriter w) { + w.run.run(); + } + }, 10); + for(Object worldConfigurationObj : (List)configuration.getProperty("worlds")) { Map worldConfiguration = (Map)worldConfigurationObj; String worldName = (String)worldConfiguration.get("name"); @@ -180,6 +204,7 @@ public class MapManager { plug_in = plugin; tileQueue.start(); + writeQueue.start(); } @@ -329,18 +354,20 @@ public class MapManager { public void startRendering() { tileQueue.start(); + writeQueue.start(); } public void stopRendering() { tileQueue.stop(); + writeQueue.stop(); } public boolean render(MapTile tile) { boolean result = tile.getMap().render(tile, getTileFile(tile)); - pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename())); + //Do update after async file write + return result; - } - + } private HashMap worldTileDirectories = new HashMap(); private File getTileFile(MapTile tile) { @@ -377,4 +404,10 @@ public class MapManager { return new Object[0]; return world.updates.getUpdatedObjects(since); } + + public void enqueueImageWrite(Runnable run) { + ImageWriter handler = new ImageWriter(); + handler.run = run; + writeQueue.push(handler); + } } diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index bd75b31b..2aaa6d53 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -11,8 +11,10 @@ import javax.imageio.ImageIO; import org.bukkit.Location; import org.bukkit.World; +import org.dynmap.Client; import org.dynmap.ColorScheme; import org.dynmap.DynmapChunk; +import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; import org.dynmap.debug.Debug; @@ -120,15 +122,26 @@ public class FlatMap extends MapType { raster.setPixel(t.size-y-1, x, pixel); rendered = true; } + /* Hand encoding and writing file off to MapManager */ + final File fname = outputFile; + 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())); + } + }); - try { - ImageIO.write(im, "png", outputFile); - } catch (IOException e) { - Debug.error("Failed to save image: " + outputFile.getPath(), e); - } catch (java.lang.NullPointerException e) { - Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e); - } - im.flush(); return rendered; } diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index 9fb8e2a7..b19d5d9a 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -11,7 +11,10 @@ import java.util.Map; import javax.imageio.ImageIO; import org.bukkit.World; +import org.dynmap.Client; import org.dynmap.ColorScheme; +import org.dynmap.MapManager; +import org.dynmap.MapTile; import org.dynmap.debug.Debug; public class DefaultTileRenderer implements MapTileRenderer { @@ -104,12 +107,28 @@ public class DefaultTileRenderer implements MapTileRenderer { iz--; } - /* save the generated tile */ - saveImage(im, outputFile); - im.flush(); - - tile.file = outputFile; - ((KzedMap) tile.getMap()).invalidateTile(new KzedZoomedMapTile(world, (KzedMap) tile.getMap(), tile)); + /* Hand encoding and writing file off to MapManager */ + final File fname = outputFile; + final KzedMapTile 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(); + mtile.file = fname; + ((KzedMap)mtile.getMap()).invalidateTile( + new KzedZoomedMapTile(mtile.getWorld(), (KzedMap) mtile.getMap(), mtile)); + MapManager.mapman.pushUpdate(mtile.getWorld(), + new Client.Tile(mtile.getFilename())); + } + }); return !isempty; } @@ -170,17 +189,4 @@ public class DefaultTileRenderer implements MapTileRenderer { } } } - - /* save rendered tile, update zoom-out tile */ - public void saveImage(BufferedImage im, File outputFile) { - Debug.debug("saving image " + outputFile.getPath()); - /* save image */ - try { - ImageIO.write(im, "png", outputFile); - } catch (IOException e) { - Debug.error("Failed to save image: " + outputFile.getPath(), e); - } catch (java.lang.NullPointerException e) { - Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e); - } - } } diff --git a/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java b/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java index 468f7ff1..643d585d 100644 --- a/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java @@ -9,79 +9,89 @@ 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) { } - public void render(KzedZoomedMapTile zt, File outputPath) { - KzedMapTile originalTile = zt.originalTile; - int px = originalTile.px; - int py = originalTile.py; - int zpx = zt.getTileX(); - int zpy = zt.getTileY(); + public void render(final KzedZoomedMapTile zt, final File outputPath) { + /* Hand it all to map manager write thread */ + MapManager.mapman.enqueueImageWrite(new Runnable() { + public void run() { + KzedMapTile originalTile = zt.originalTile; + int px = originalTile.px; + int py = originalTile.py; + int zpx = zt.getTileX(); + int zpy = zt.getTileY(); - BufferedImage image = null; - try { - image = ImageIO.read(originalTile.file); - } catch (IOException e) { - } catch (IndexOutOfBoundsException e) { - } + BufferedImage image = null; + try { + image = ImageIO.read(originalTile.file); + } catch (IOException e) { + } catch (IndexOutOfBoundsException e) { + } - if (image == null) { - Debug.debug("Could not load original tile, won't render zoom-out tile."); - return; - } + if (image == null) { + Debug.debug("Could not load original tile, won't render zoom-out tile."); + return; + } - BufferedImage zIm = null; - File zoomFile = outputPath; - try { - zIm = ImageIO.read(zoomFile); - } catch (IOException e) { - } catch (IndexOutOfBoundsException e) { - } + BufferedImage zIm = null; + File zoomFile = outputPath; + 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 " + zt.getFilename()); - } else { - Debug.debug("Loaded zoom-out tile from " + zt.getFilename()); - } + if (zIm == null) { + /* create new one */ + zIm = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); + Debug.debug("New zoom-out tile created " + zt.getFilename()); + } else { + Debug.debug("Loaded zoom-out tile from " + zt.getFilename()); + } + /* update zoom-out tile */ - /* update zoom-out tile */ + /* 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; + /* blit scaled rendered tile onto zoom-out tile */ + // WritableRaster zr = zIm.getRaster(); + Graphics2D g2 = zIm.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2.drawImage(image, ox, oy, scw, sch, null); - /* blit scaled rendered tile onto zoom-out tile */ - // WritableRaster zr = zIm.getRaster(); - Graphics2D g2 = zIm.createGraphics(); - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g2.drawImage(image, ox, oy, scw, sch, null); + image.flush(); - image.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(); + /* 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(); + + MapManager.mapman.pushUpdate(zt.getWorld(), + new Client.Tile(zt.getFilename())); + + } + }); } }