diff --git a/configuration.txt b/configuration.txt index c4b6b5d5..159ef936 100644 --- a/configuration.txt +++ b/configuration.txt @@ -65,9 +65,6 @@ display-whitelist: false # How often a tile gets rendered (in seconds). renderinterval: 1 -# Do render on main thread - may generate more server load, but safer and fixes broken tiles -renderonsync: true - render-triggers: # - chunkloaded # - playermove @@ -90,11 +87,8 @@ webserver-port: 8123 # Disables Webserver portion of Dynmap (Advanced users only) disable-webserver: false -# Use timesliced fullrender - takes a bit longer, but much more polite for server -timeslicerender: true - -# Period between tile renders for timesliced fullrender, in seconds -timesliceinterval: 0.5 +# Period between tile renders for fullrender, in seconds (non-zero to pace fullrenders, lessen CPU load) +timesliceinterval: 0.0 # Interval the browser should poll for updates. updaterate: 2000 @@ -140,6 +134,8 @@ templates: # shadowstrength: 1.0 # To render a world as a "night view", set shadowstrength and ambientlight # ambientlight: 4 + # To render both night and day versions of tiles (when ambientlight is set), set true + # night-and-day: true # Sets the icon to 'images/block_custom.png' # icon: custom #- class: org.dynmap.kzedmap.HighlightTileRenderer @@ -222,6 +218,8 @@ worlds: # # shadowstrength: 1.0 # # To render a world as a "night view", set shadowstrength and ambientlight # # ambientlight: 4 + # # To render both night and day versions of tiles (when ambientlight is set), set true + # # night-and-day: true # # Sets the icon to 'images/block_custom.png' # # icon: custom # #- class: org.dynmap.kzedmap.HighlightTileRenderer diff --git a/src/main/java/org/dynmap/ColorScheme.java b/src/main/java/org/dynmap/ColorScheme.java index 37b77d03..86520dbb 100644 --- a/src/main/java/org/dynmap/ColorScheme.java +++ b/src/main/java/org/dynmap/ColorScheme.java @@ -43,7 +43,6 @@ public class ColorScheme { Color[][] colors = new Color[256][]; Color[][][] datacolors = new Color[256][][]; InputStream stream; - boolean enab_datacolor = MapManager.mapman.doSyncRender(); try { Debug.debug("Loading colors from '" + colorSchemeFile + "'..."); stream = new FileInputStream(colorSchemeFile); @@ -79,15 +78,13 @@ public class ColorScheme { c[2] = new Color(Integer.parseInt(split[13]), Integer.parseInt(split[14]), Integer.parseInt(split[15]), Integer.parseInt(split[16])); if(dat != null) { - if(enab_datacolor) { - Color[][] dcolor = datacolors[id]; /* Existing list? */ - if(dcolor == null) { - dcolor = new Color[16][]; /* Make 16 index long list */ - datacolors[id] = dcolor; - } - if((dat >= 0) && (dat < 16)) { /* Add color to list */ - dcolor[dat] = c; - } + Color[][] dcolor = datacolors[id]; /* Existing list? */ + if(dcolor == null) { + dcolor = new Color[16][]; /* Make 16 index long list */ + datacolors[id] = dcolor; + } + if((dat >= 0) && (dat < 16)) { /* Add color to list */ + dcolor[dat] = c; } if(dat == 0) { /* Index zero is base color too */ colors[id] = c; diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index c16f789a..88760b5f 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -1,7 +1,6 @@ package org.dynmap; import java.io.File; -import java.util.HashMap; import java.io.IOException; import java.lang.reflect.Constructor; import java.net.InetAddress; @@ -12,7 +11,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.Collections; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.World.Environment; @@ -300,35 +298,30 @@ public class DynmapPlugin extends JavaPlugin { sender.sendMessage("Queued " + invalidates + " tiles" + (invalidates == 0 ? " (world is not loaded?)" : "...")); - return true; } } else if (c.equals("hide")) { if (args.length == 1) { if(player != null && checkPlayerPermission(sender,"hide.self")) { playerList.setVisible(player.getName(),false); sender.sendMessage("You are now hidden on Dynmap."); - return true; } } else if (checkPlayerPermission(sender,"hide.others")) { for (int i = 1; i < args.length; i++) { playerList.setVisible(args[i],false); sender.sendMessage(args[i] + " is now hidden on Dynmap."); } - return true; } } else if (c.equals("show")) { if (args.length == 1) { if(player != null && checkPlayerPermission(sender,"show.self")) { playerList.setVisible(player.getName(),true); sender.sendMessage("You are now visible on Dynmap."); - return true; } } else if (checkPlayerPermission(sender,"show.others")) { for (int i = 1; i < args.length; i++) { playerList.setVisible(args[i],true); sender.sendMessage(args[i] + " is now visible on Dynmap."); } - return true; } } else if (c.equals("fullrender") && checkPlayerPermission(sender,"fullrender")) { if (args.length > 1) { @@ -336,19 +329,20 @@ public class DynmapPlugin extends JavaPlugin { World w = getServer().getWorld(args[i]); if(w != null) mapManager.renderFullWorld(new Location(w, 0, 0, 0)); + else + sender.sendMessage("World '" + args[i] + "' not defined/loaded"); } - return true; } else if (player != null) { Location loc = player.getLocation(); if(loc != null) mapManager.renderFullWorld(loc); - return true; + } else { + sender.sendMessage("World name is required"); } } else if (c.equals("reload") && checkPlayerPermission(sender, "reload")) { sender.sendMessage("Reloading Dynmap..."); reload(); sender.sendMessage("Dynmap reloaded"); - return true; } return true; } diff --git a/src/main/java/org/dynmap/MapChunkCache.java b/src/main/java/org/dynmap/MapChunkCache.java index 7813e3c3..b59d954f 100644 --- a/src/main/java/org/dynmap/MapChunkCache.java +++ b/src/main/java/org/dynmap/MapChunkCache.java @@ -7,9 +7,7 @@ import org.bukkit.Chunk; import org.bukkit.entity.Entity; /** - * Container for managing chunks, as well as abstracting the different methods we may - * handle chunk data (existing chunk loading, versus upcoming chunk snapshots) - * + * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ public class MapChunkCache { private World w; @@ -21,71 +19,22 @@ public class MapChunkCache { private int x_dim; private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */ - private LinkedList loadedChunks = new LinkedList(); - + /** * Iterator for traversing map chunk cache (base is for non-snapshot) */ public class MapIterator { public int x, y, z; + private ChunkSnapshot snap; + private int x4, z4; + MapIterator(int x0, int y0, int z0) { initialize(x0, y0, z0); } - public void initialize(int x0, int y0, int z0) { + public final void initialize(int x0, int y0, int z0) { this.x = x0; this.y = y0; - this.z = z0; - } - public int getBlockTypeID() { - return w.getBlockTypeIdAt(x, y, z); - } - public int getBlockData() { - return w.getBlockAt(x, y, z).getData(); - } - public int getHighestBlockYAt() { - return w.getHighestBlockYAt(x, z); - } - public int getBlockSkyLight() { - return 15; - } - public int getBlockEmittedLight() { - return 0; - } - public void incrementX() { - x++; - } - public void decrementX() { - x--; - } - public void incrementY() { - y++; - } - public void decrementY() { - y--; - } - public void incrementZ() { - z++; - } - public void decrementZ() { - z--; - } - public void setY(int y) { - this.y = y; - } - } - - /** - * Iterator for snapshot mode - */ - public class SnapshotMapIterator extends MapIterator { - private ChunkSnapshot snap; - private int x4, z4; - - public SnapshotMapIterator(int x0, int y0, int z0) { - super(x0, y0, z0); - } - public void initialize(int x0, int y0, int z0) { - super.initialize(x0, y0, z0); + this.z = z0; try { snap = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; } catch (ArrayIndexOutOfBoundsException aioobx) { @@ -94,22 +43,22 @@ public class MapChunkCache { x4 = x0 & 0xF; z4 = z0 & 0xF; } - public int getBlockTypeID() { + public final int getBlockTypeID() { return snap.getBlockTypeId(x4, y, z4); } - public int getBlockData() { + public final int getBlockData() { return snap.getBlockData(x4, y, z4); } - public int getHighestBlockYAt() { + public final int getHighestBlockYAt() { return snap.getHighestBlockYAt(x4, z4); } - public int getBlockSkyLight() { + public final int getBlockSkyLight() { return snap.getBlockSkyLight(x4, y, z4); } - public int getBlockEmittedLight() { + public final int getBlockEmittedLight() { return snap.getBlockEmittedLight(x4, y, z4); } - public void incrementX() { + public final void incrementX() { x++; x4 = x & 0xF; if(x4 == 0) { /* Next chunk? */ try { @@ -119,7 +68,7 @@ public class MapChunkCache { } } } - public void decrementX() { + public final void decrementX() { x--; x4 = x & 0xF; if(x4 == 15) { /* Next chunk? */ try { @@ -129,13 +78,13 @@ public class MapChunkCache { } } } - public void incrementY() { + public final void incrementY() { y++; } - public void decrementY() { + public final void decrementY() { y--; } - public void incrementZ() { + public final void incrementZ() { z++; z4 = z & 0xF; if(z4 == 0) { /* Next chunk? */ try { @@ -145,7 +94,7 @@ public class MapChunkCache { } } } - public void decrementZ() { + public final void decrementZ() { z--; z4 = z & 0xF; if(z4 == 15) { /* Next chunk? */ try { @@ -155,7 +104,11 @@ public class MapChunkCache { } } } - } + public final void setY(int y) { + this.y = y; + } + } + /** * Chunk cache for representing unloaded chunk */ @@ -226,13 +179,13 @@ public class MapChunkCache { initialized = true; if(gethandle != null) Log.info("Chunk snapshot support enabled"); - else - Log.info("Chunk snapshot support disabled"); + else { + Log.severe("ERROR: Chunk snapshot support not found - rendering not functiona!l"); + return; + } } - if(gethandle != null) { /* We can use caching */ - snaparray = new ChunkSnapshot[x_dim * (z_max-z_min+1)]; - } - if(snaparray != null) { + snaparray = new ChunkSnapshot[x_dim * (z_max-z_min+1)]; + if(gethandle != null) { // Load the required chunks. for (DynmapChunk chunk : chunks) { boolean wasLoaded = w.isChunkLoaded(chunk.x, chunk.z); @@ -265,19 +218,11 @@ public class MapChunkCache { w.unloadChunk(chunk.x, chunk.z, false, false); } } - for(int i = 0; i < snaparray.length; i++) { - if(snaparray[i] == null) - snaparray[i] = EMPTY; - } } - else { /* Else, load and keep them loaded for now */ - // Load the required chunks. - for (DynmapChunk chunk : chunks) { - boolean wasLoaded = w.isChunkLoaded(chunk.x, chunk.z); - boolean didload = w.loadChunk(chunk.x, chunk.z, false); - if ((!wasLoaded) && didload) - loadedChunks.add(chunk); - } + /* Fill missing chunks with empty dummy chunk */ + for(int i = 0; i < snaparray.length; i++) { + if(snaparray[i] == null) + snaparray[i] = EMPTY; } } /** @@ -288,91 +233,46 @@ public class MapChunkCache { for(int i = 0; i < snaparray.length; i++) { snaparray[i] = null; } - } - else { - while (!loadedChunks.isEmpty()) { - DynmapChunk c = loadedChunks.pollFirst(); - /* It looks like bukkit "leaks" entities - they don't get removed from the world-level table - * when chunks are unloaded but not saved - removing them seems to do the trick */ - Chunk cc = w.getChunkAt(c.x, c.z); - if(cc != null) { - for(Entity e: cc.getEntities()) - e.remove(); - } - /* Since we only remember ones we loaded, and we're synchronous, no player has - * moved, so it must be safe (also prevent chunk leak, which appears to happen - * because isChunkInUse defined "in use" as being within 256 blocks of a player, - * 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(c.x, c.z, false, false); - } + snaparray = null; } } /** * Get block ID at coordinates */ public int getBlockTypeID(int x, int y, int z) { - if(snaparray != null) { - ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; - return ss.getBlockTypeId(x & 0xF, y, z & 0xF); - } - else { - return w.getBlockTypeIdAt(x, y, z); - } + ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; + return ss.getBlockTypeId(x & 0xF, y, z & 0xF); } /** * Get block data at coordiates */ public byte getBlockData(int x, int y, int z) { - if(snaparray != null) { - ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; - return (byte)ss.getBlockData(x & 0xF, y, z & 0xF); - } - else { - return w.getBlockAt(x, y, z).getData(); - } + ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; + return (byte)ss.getBlockData(x & 0xF, y, z & 0xF); } /* Get highest block Y * */ public int getHighestBlockYAt(int x, int z) { - if(snaparray != null) { - ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; - return ss.getHighestBlockYAt(x & 0xF, z & 0xF); - } - else { - return w.getHighestBlockYAt(x, z); - } + ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; + return ss.getHighestBlockYAt(x & 0xF, z & 0xF); } /* Get sky light level */ public int getBlockSkyLight(int x, int y, int z) { - if(snaparray != null) { - ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; - return ss.getBlockSkyLight(x & 0xF, y, z & 0xF); - } - else { - return 15; - } + ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; + return ss.getBlockSkyLight(x & 0xF, y, z & 0xF); } /* Get emitted light level */ public int getBlockEmittedLight(int x, int y, int z) { - if(snaparray != null) { - ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; - return ss.getBlockEmittedLight(x & 0xF, y, z & 0xF); - } - else { - return 0; - } + ChunkSnapshot ss = snaparray[((x>>4) - x_min) + ((z>>4) - z_min) * x_dim]; + return ss.getBlockEmittedLight(x & 0xF, y, z & 0xF); } /** * Get cache iterator */ public MapIterator getIterator(int x, int y, int z) { - if(snaparray != null) - return new SnapshotMapIterator(x, y, z); - else - return new MapIterator(x, y, z); + return new MapIterator(x, y, z); } } diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 9b60370c..782444d9 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -8,24 +8,24 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; - -import org.bukkit.Chunk; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.entity.Entity; import org.bukkit.scheduler.BukkitScheduler; import org.dynmap.debug.Debug; public class MapManager { public AsynchronousQueue tileQueue; - public AsynchronousQueue writeQueue; public List worlds = new ArrayList(); public Map worldsLookup = new HashMap(); private BukkitScheduler scheduler; private DynmapPlugin plug_in; - private double timeslice_interval = 0.0; - /* Which timesliced renders are active */ + private long timeslice_int = 0; /* In milliseconds */ + /* Which fullrenders are active */ private HashMap active_renders = new HashMap(); /* lock for our data structures */ @@ -33,9 +33,9 @@ public class MapManager { public static MapManager mapman; /* Our singleton */ - private static class ImageWriter { - Runnable run; - } + /* Thread pool for processing renders */ + private ScheduledThreadPoolExecutor renderpool; + private static final int POOL_SIZE = 3; public DynmapWorld getWorld(String name) { DynmapWorld world = worldsLookup.get(name); @@ -46,6 +46,7 @@ public class MapManager { return worlds; } + /* This always runs on render pool threads - no bukkit calls from here */ private class FullWorldRenderState implements Runnable { DynmapWorld world; /* Which world are we rendering */ Location loc; @@ -74,7 +75,8 @@ public class MapManager { public void run() { MapTile tile; - + long tstart = System.currentTimeMillis(); + if(tile0 == null) { /* Not single tile render */ /* If render queue is empty, start next map */ if(renderQueue.isEmpty()) { @@ -87,8 +89,10 @@ public class MapManager { rendercnt = 0; map_index++; /* Next map */ if(map_index >= world.maps.size()) { /* Last one done? */ - Log.info("Full render finished."); - active_renders.remove(world.world.getName()); + Log.info("Full render of '" + world.world.getName() + "' finished."); + synchronized(lock) { + active_renders.remove(world.world.getName()); + } return; } map = world.maps.get(map_index); @@ -116,9 +120,13 @@ public class MapManager { else { /* Else, single tile render */ tile = tile0; } - DynmapChunk[] requiredChunks = tile.getMap().getRequiredChunks(tile); - MapChunkCache cache = new MapChunkCache(world.world, requiredChunks); World w = world.world; + /* Fetch chunk cache from server thread */ + DynmapChunk[] requiredChunks = tile.getMap().getRequiredChunks(tile); + MapChunkCache cache = createMapChunkCache(w, requiredChunks); + if(cache == null) { + return; /* Cancelled/aborted */ + } if(tile0 != null) { /* Single tile? */ render(cache, tile); /* Just render */ } @@ -143,8 +151,13 @@ public class MapManager { /* And unload what we loaded */ cache.unloadChunks(); if(tile0 == null) { /* fullrender */ - /* Schedule the next tile to be worked */ - scheduler.scheduleSyncDelayedTask(plug_in, this, (int)(timeslice_interval*20)); + long tend = System.currentTimeMillis(); + if(timeslice_int > (tend-tstart)) { /* We were fast enough */ + renderpool.schedule(this, timeslice_int - (tend-tstart), TimeUnit.MILLISECONDS); + } + else { /* Schedule to run ASAP */ + renderpool.execute(this); + } } } } @@ -156,25 +169,16 @@ public class MapManager { this.tileQueue = new AsynchronousQueue(new Handler() { @Override public void handle(MapTile t) { - scheduler.scheduleSyncDelayedTask(plug_in, - new FullWorldRenderState(t), 1); + renderpool.execute(new FullWorldRenderState(t)); } }, (int) (configuration.getDouble("renderinterval", 0.5) * 1000)); - this.writeQueue = new AsynchronousQueue( - new Handler() { - @Override - public void handle(ImageWriter w) { - w.run.run(); - } - }, 10); - - timeslice_interval = configuration.getDouble("timesliceinterval", 0.5); + /* On dedicated thread, so default to no delays */ + timeslice_int = (long)(configuration.getDouble("timesliceinterval", 0.0) * 1000); scheduler = plugin.getServer().getScheduler(); tileQueue.start(); - writeQueue.start(); for (World world : plug_in.getServer().getWorlds()) { activateWorld(world); @@ -188,16 +192,19 @@ public class MapManager { return; } String wname = l.getWorld().getName(); - FullWorldRenderState rndr = active_renders.get(wname); - if(rndr != null) { - Log.info("Full world render of world '" + wname + "' already active."); - return; + FullWorldRenderState rndr; + synchronized(lock) { + rndr = active_renders.get(wname); + if(rndr != null) { + Log.info("Full world render of world '" + wname + "' already active."); + return; + } + rndr = new FullWorldRenderState(world,l); /* Make new activation record */ + active_renders.put(wname, rndr); /* Add to active table */ } - rndr = new FullWorldRenderState(world,l); /* Make new activation record */ - active_renders.put(wname, rndr); /* Add to active table */ /* Schedule first tile to be worked */ - scheduler.scheduleSyncDelayedTask(plug_in, rndr, (int)(timeslice_interval*20)); - Log.info("Full render starting on world '" + wname + "' (timesliced)..."); + renderpool.execute(rndr); + Log.info("Full render starting on world '" + wname + "'..."); } public void activateWorld(World w) { @@ -282,12 +289,15 @@ public class MapManager { public void startRendering() { tileQueue.start(); - writeQueue.start(); + renderpool = new ScheduledThreadPoolExecutor(POOL_SIZE); } public void stopRendering() { + if(renderpool != null) { + renderpool.shutdown(); + renderpool = null; + } tileQueue.stop(); - writeQueue.stop(); } public boolean render(MapChunkCache cache, MapTile tile) { @@ -333,13 +343,21 @@ public class MapManager { return world.updates.getUpdatedObjects(since); } - public void enqueueImageWrite(Runnable run) { - ImageWriter handler = new ImageWriter(); - handler.run = run; - writeQueue.push(handler); - } - - public boolean doSyncRender() { - return true; + /** + * Render processor helper - used by code running on render threads to request chunk snapshot cache from server/sync thread + */ + public MapChunkCache createMapChunkCache(final World w, final DynmapChunk[] chunks) { + Callable job = new Callable() { + public MapChunkCache call() { + return new MapChunkCache(w, chunks); + } + }; + Future rslt = scheduler.callSyncMethod(plug_in, job); + try { + return rslt.get(); + } catch (Exception x) { + Log.info("createMapChunk - " + x); + return null; + } } } diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index a87b0105..f64cd00a 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -4,7 +4,6 @@ import static org.dynmap.JSONUtils.a; import static org.dynmap.JSONUtils.s; import java.awt.image.BufferedImage; -import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; @@ -199,26 +198,18 @@ public class FlatMap extends MapType { 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); - } - KzedMap.freeBufferedImage(img); - MapManager.mapman.pushUpdate(mtile.getWorld(), - new Client.Tile(mtile.getFilename())); - } - }); - + Debug.debug("saving image " + outputFile.getPath()); + 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); + } + KzedMap.freeBufferedImage(im); + MapManager.mapman.pushUpdate(tile.getWorld(), + new Client.Tile(tile.getFilename())); + return rendered; } diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index a8121ea9..209f4761 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -2,11 +2,7 @@ package org.dynmap.kzedmap; import static org.dynmap.JSONUtils.a; import static org.dynmap.JSONUtils.s; - -import java.awt.Graphics2D; -import java.awt.RenderingHints; import java.awt.image.BufferedImage; -import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.util.HashSet; @@ -19,7 +15,6 @@ import org.dynmap.Client; import org.dynmap.Color; import org.dynmap.ColorScheme; import org.dynmap.ConfigurationNode; -import org.dynmap.Log; import org.dynmap.MapManager; import org.dynmap.debug.Debug; import org.dynmap.MapChunkCache; @@ -226,21 +221,11 @@ public class DefaultTileRenderer implements MapTileRenderer { } /* Hand encoding and writing file off to MapManager */ - final File fname = outputFile; - final KzedMapTile mtile = tile; - final BufferedImage img = im; - final BufferedImage zimg = zim; - final BufferedImage img_day = im_day; - final BufferedImage zimg_day = zim_day; - final KzedZoomedMapTile zmtile = new KzedZoomedMapTile(mtile.getWorld(), - (KzedMap) mtile.getMap(), mtile); - final File zoomFile = MapManager.mapman.getTileFile(zmtile); + KzedZoomedMapTile zmtile = new KzedZoomedMapTile(tile.getWorld(), + (KzedMap) tile.getMap(), tile); + File zoomFile = MapManager.mapman.getTileFile(zmtile); - MapManager.mapman.enqueueImageWrite(new Runnable() { - public void run() { - doFileWrites(fname, mtile, img, img_day, zmtile, zoomFile, zimg, zimg_day); - } - }); + doFileWrites(outputFile, tile, im, im_day, zmtile, zoomFile, zim, zim_day); return !isempty; }