diff --git a/src/main/java/org/dynmap/AsynchronousQueue.java b/src/main/java/org/dynmap/AsynchronousQueue.java new file mode 100644 index 00000000..7eacca1b --- /dev/null +++ b/src/main/java/org/dynmap/AsynchronousQueue.java @@ -0,0 +1,108 @@ +package org.dynmap; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class AsynchronousQueue { + protected static final Logger log = Logger.getLogger("Minecraft"); + + private Object lock = new Object(); + private Thread thread; + private LinkedList queue = new LinkedList(); + private Set set = new HashSet(); + private Handler handler; + private int dequeueTime; + + public AsynchronousQueue(Handler handler, int dequeueTime) { + this.handler = handler; + this.dequeueTime = dequeueTime; + } + + public boolean push(T t) { + synchronized (lock) { + if (set.add(t)) { + queue.addLast(t); + return true; + } + return false; + } + } + + private T pop() { + synchronized (lock) { + try { + T t = queue.removeFirst(); + if (!set.remove(t)) { + // This should never happen. + } + return t; + } catch (NoSuchElementException e) { + return null; + } + } + } + + public int size() { + return set.size(); + } + + public void start() { + synchronized (lock) { + thread = new Thread(new Runnable() { + @Override + public void run() { + running(); + } + }); + thread.start(); + try { + thread.setPriority(Thread.MIN_PRIORITY); + } catch (SecurityException e) { + log.info("Failed to set minimum priority for worker thread!"); + } + } + } + + public void stop() { + synchronized (lock) { + if (thread == null) + return; + Thread oldThread = thread; + thread = null; + + log.info("Stopping map renderer..."); + + try { + oldThread.join(); + } catch (InterruptedException e) { + log.info("Waiting for map renderer to stop is interrupted"); + } + } + } + + private void running() { + try { + while (Thread.currentThread() == thread) { + T t = pop(); + if (t != null) { + handler.handle(t); + } + sleep(dequeueTime); + } + + } catch (Exception ex) { + log.log(Level.SEVERE, "Exception on rendering-thread", ex); + } + } + + private void sleep(int time) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + } + } +} diff --git a/src/main/java/org/dynmap/DynmapBlockListener.java b/src/main/java/org/dynmap/DynmapBlockListener.java index f1cf4367..41a8b61c 100644 --- a/src/main/java/org/dynmap/DynmapBlockListener.java +++ b/src/main/java/org/dynmap/DynmapBlockListener.java @@ -16,13 +16,13 @@ public class DynmapBlockListener extends BlockListener { @Override public void onBlockPlace(BlockPlaceEvent event) { Block blockPlaced = event.getBlockPlaced(); - mgr.touch(blockPlaced.getX(), blockPlaced.getY(), blockPlaced.getZ()); + mgr.touch(blockPlaced.getLocation()); } public void onBlockDamage(BlockDamageEvent event) { if (event.getDamageLevel() == BlockDamageLevel.BROKEN) { Block blockBroken = event.getBlock(); - mgr.touch(blockBroken.getX(), blockBroken.getY(), blockBroken.getZ()); + mgr.touch(blockBroken.getLocation()); } } } diff --git a/src/main/java/org/dynmap/DynmapPlayerListener.java b/src/main/java/org/dynmap/DynmapPlayerListener.java index 7c98da1b..d54e2000 100644 --- a/src/main/java/org/dynmap/DynmapPlayerListener.java +++ b/src/main/java/org/dynmap/DynmapPlayerListener.java @@ -31,7 +31,7 @@ public class DynmapPlayerListener extends PlayerListener { if (split[1].equals("render")) { Player player = event.getPlayer(); - mgr.touch(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ()); + mgr.touch(player.getLocation()); event.setCancelled(true); } else if (split[1].equals("hide")) { if (split.length == 2) { diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index e3aab1ea..5336b17d 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -17,7 +17,8 @@ import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginLoader; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.config.Configuration; -import org.dynmap.debug.BukkitPlayerDebugger; +import org.dynmap.debug.Debug; +import org.dynmap.debug.LogDebugger; import org.dynmap.web.HttpServer; import org.dynmap.web.handlers.ClientConfigurationHandler; import org.dynmap.web.handlers.ClientUpdateHandler; @@ -32,8 +33,7 @@ public class DynmapPlugin extends JavaPlugin { private PlayerList playerList; private Configuration configuration; - private BukkitPlayerDebugger debugger = new BukkitPlayerDebugger(this); - + public static File tilesDirectory; public static File dataRoot; public DynmapPlugin(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File folder, File plugin, ClassLoader cLoader) { @@ -54,15 +54,18 @@ public class DynmapPlugin extends JavaPlugin { } public void onEnable() { + Debug.addDebugger(new LogDebugger()); + configuration = new Configuration(new File(this.getDataFolder(), "configuration.txt")); configuration.load(); - debugger.enable(); + tilesDirectory = getFile(configuration.getString("tilespath", "web/tiles")); + playerList = new PlayerList(getServer()); playerList.load(); - mapManager = new MapManager(getWorld(), debugger, configuration); - mapManager.startManager(); + mapManager = new MapManager(configuration); + mapManager.startRendering(); InetAddress bindAddress; { @@ -78,8 +81,8 @@ public class DynmapPlugin extends JavaPlugin { int port = configuration.getInt("webserver-port", 8123); webServer = new HttpServer(bindAddress, port); - webServer.handlers.put("/", new FilesystemHandler(mapManager.webDirectory)); - webServer.handlers.put("/tiles/", new FilesystemHandler(mapManager.tileDirectory)); + webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")))); + webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory)); webServer.handlers.put("/up/", new ClientUpdateHandler(mapManager, playerList, getWorld())); webServer.handlers.put("/up/configuration", new ClientConfigurationHandler((Map) configuration.getProperty("web"))); @@ -93,13 +96,13 @@ public class DynmapPlugin extends JavaPlugin { } public void onDisable() { - mapManager.stopManager(); + mapManager.stopRendering(); if (webServer != null) { webServer.shutdown(); webServer = null; } - debugger.disable(); + Debug.clearDebuggers(); } public void registerEvents() { @@ -111,4 +114,18 @@ public class DynmapPlugin extends JavaPlugin { getServer().getPluginManager().registerEvent(Event.Type.PLAYER_COMMAND, playerListener, Priority.Normal, this); getServer().getPluginManager().registerEvent(Event.Type.PLAYER_CHAT, playerListener, Priority.Normal, this); } + + private static File combinePaths(File parent, String path) { + return combinePaths(parent, new File(path)); + } + + private static File combinePaths(File parent, File path) { + if (path.isAbsolute()) + return path; + return new File(parent, path.getPath()); + } + + public File getFile(String path) { + return combinePaths(DynmapPlugin.dataRoot, path); + } } diff --git a/src/main/java/org/dynmap/Event.java b/src/main/java/org/dynmap/Event.java new file mode 100644 index 00000000..9cba4e97 --- /dev/null +++ b/src/main/java/org/dynmap/Event.java @@ -0,0 +1,26 @@ +package org.dynmap; + +import java.util.LinkedList; +import java.util.List; + +public class Event { + private List> listeners = new LinkedList>(); + + public synchronized void addListener(Listener l) { + listeners.add(l); + } + + public synchronized void removeListener(Listener l) { + listeners.remove(l); + } + + public synchronized void trigger(T t) { + for (Listener l : listeners) { + l.triggered(t); + } + } + + public interface Listener { + void triggered(T t); + } +} diff --git a/src/main/java/org/dynmap/Handler.java b/src/main/java/org/dynmap/Handler.java new file mode 100644 index 00000000..2a72acd4 --- /dev/null +++ b/src/main/java/org/dynmap/Handler.java @@ -0,0 +1,5 @@ +package org.dynmap; + +public interface Handler { + void handle(T t); +} diff --git a/src/main/java/org/dynmap/MapLocation.java b/src/main/java/org/dynmap/MapLocation.java deleted file mode 100644 index 854ae5c0..00000000 --- a/src/main/java/org/dynmap/MapLocation.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.dynmap; - -public class MapLocation { - public float x; - public float y; -} diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index 7a926377..ccfd0fb5 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -3,84 +3,48 @@ package org.dynmap; import java.io.File; import java.lang.reflect.Constructor; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.logging.Level; import java.util.logging.Logger; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.util.config.ConfigurationNode; -import org.dynmap.debug.Debugger; +import org.dynmap.debug.Debug; -public class MapManager extends Thread { +public class MapManager { protected static final Logger log = Logger.getLogger("Minecraft"); - private World world; - private Debugger debugger; - private MapType[] maps; - public StaleQueue staleQueue; + private MapType[] mapTypes; + public AsynchronousQueue tileQueue; public UpdateQueue updateQueue; public PlayerList playerList; /* lock for our data structures */ public static final Object lock = new Object(); - /* whether the worker thread should be running now */ - private boolean running = false; - - /* path to image tile directory */ - public File tileDirectory; - - /* web files location */ - public File webDirectory; - - /* bind web server to ip-address */ - public String bindaddress = "0.0.0.0"; - - /* port to run web server on */ - public int serverport = 8123; - - /* time to pause between rendering tiles (ms) */ - public int renderWait = 500; - - public boolean loadChunks = true; - - public void debug(String msg) { - debugger.debug(msg); - } - - private static File combinePaths(File parent, String path) { - return combinePaths(parent, new File(path)); - } - - private static File combinePaths(File parent, File path) { - if (path.isAbsolute()) - return path; - return new File(parent, path.getPath()); - } - - public MapManager(World world, Debugger debugger, ConfigurationNode configuration) { - this.world = world; - this.debugger = debugger; - this.staleQueue = new StaleQueue(); + public MapManager(ConfigurationNode configuration) { this.updateQueue = new UpdateQueue(); - - tileDirectory = combinePaths(DynmapPlugin.dataRoot, configuration.getString("tilespath", "web/tiles")); - webDirectory = combinePaths(DynmapPlugin.dataRoot, configuration.getString("webpath", "web")); - renderWait = (int) (configuration.getDouble("renderinterval", 0.5) * 1000); - loadChunks = configuration.getBoolean("loadchunks", true); - - if (!tileDirectory.isDirectory()) - tileDirectory.mkdirs(); - - maps = loadMapTypes(configuration); + this.tileQueue = new AsynchronousQueue(new Handler() { + @Override + public void handle(MapTile t) { + render(t); + } + }, (int) (configuration.getDouble("renderinterval", 0.5) * 1000)); + + mapTypes = loadMapTypes(configuration); + + tileQueue.start(); } void renderFullWorld(Location l) { - debugger.debug("Full render starting..."); - for (MapType map : maps) { + World world = l.getWorld(); + log.info("Full render starting..."); + for (MapType map : mapTypes) { int requiredChunkCount = 200; HashSet found = new HashSet(); HashSet rendered = new HashSet(); @@ -114,10 +78,10 @@ public class MapManager extends Thread { loadedChunks.add(chunk); } - if (map.render(tile)) { + if (render(tile)) { found.remove(tile); rendered.add(tile); - updateQueue.pushUpdate(new Client.Tile(tile.getName())); + updateQueue.pushUpdate(new Client.Tile(tile.getFilename())); for (MapTile adjTile : map.getAdjecentTiles(tile)) { if (!found.contains(adjTile) && !rendered.contains(adjTile)) { found.add(adjTile); @@ -135,10 +99,17 @@ public class MapManager extends Thread { world.unloadChunk(c.x, c.z, false, true); } } - debugger.debug("Full render finished."); + log.info("Full render finished."); } private MapType[] loadMapTypes(ConfigurationNode configuration) { + Event.Listener invalitateListener = new Event.Listener() { + @Override + public void triggered(MapTile t) { + invalidateTile(t); + } + }; + List configuredMaps = (List) configuration.getProperty("maps"); ArrayList mapTypes = new ArrayList(); for (Object configuredMapObj : configuredMaps) { @@ -148,83 +119,24 @@ public class MapManager extends Thread { String typeName = (String) configuredMap.get("class"); log.info("Loading map '" + typeName.toString() + "'..."); Class mapTypeClass = Class.forName(typeName); - Constructor constructor = mapTypeClass.getConstructor(MapManager.class, World.class, Debugger.class, Map.class); - MapType mapType = (MapType) constructor.newInstance(this, world, debugger, configuredMap); + Constructor constructor = mapTypeClass.getConstructor(Map.class); + MapType mapType = (MapType) constructor.newInstance(configuredMap); + mapType.onTileInvalidated.addListener(invalitateListener); mapTypes.add(mapType); } catch (Exception e) { - debugger.error("Error loading map", e); + log.log(Level.SEVERE, "Error loading maptype", e); + e.printStackTrace(); } } MapType[] result = new MapType[mapTypes.size()]; mapTypes.toArray(result); return result; } - - /* initialize and start map manager */ - public void startManager() { - synchronized (lock) { - running = true; - this.start(); - try { - this.setPriority(MIN_PRIORITY); - log.info("Set minimum priority for worker thread"); - } catch (SecurityException e) { - log.info("Failed to set minimum priority for worker thread!"); - } - } - } - - /* stop map manager */ - public void stopManager() { - synchronized (lock) { - if (!running) - return; - - log.info("Stopping map renderer..."); - running = false; - - try { - this.join(); - } catch (InterruptedException e) { - log.info("Waiting for map renderer to stop is interrupted"); - } - } - } - - /* the worker/renderer thread */ - public void run() { - try { - log.info("Map renderer has started."); - - while (running) { - MapTile t = staleQueue.popStaleTile(); - if (t != null) { - debugger.debug("Rendering tile " + t + "..."); - boolean isNonEmptyTile = t.getMap().render(t); - updateQueue.pushUpdate(new Client.Tile(t.getName())); - - try { - Thread.sleep(renderWait); - } catch (InterruptedException e) { - } - } else { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - } - } - } - - log.info("Map renderer has stopped."); - } catch (Exception ex) { - debugger.error("Exception on rendering-thread: " + ex.toString()); - ex.printStackTrace(); - } - } - - public void touch(int x, int y, int z) { - for (int i = 0; i < maps.length; i++) { - MapTile[] tiles = maps[i].getTiles(new Location(world, x, y, z)); + + public void touch(Location l) { + Debug.debug("Touched " + l.toString()); + for (int i = 0; i < mapTypes.length; i++) { + MapTile[] tiles = mapTypes[i].getTiles(l); for (int j = 0; j < tiles.length; j++) { invalidateTile(tiles[j]); } @@ -232,7 +144,32 @@ public class MapManager extends Thread { } public void invalidateTile(MapTile tile) { - debugger.debug("Invalidating tile " + tile.getName()); - staleQueue.pushStaleTile(tile); + Debug.debug("Invalidating tile " + tile.getFilename()); + tileQueue.push(tile); + } + + public void startRendering() { + tileQueue.start(); + } + + public void stopRendering() { + tileQueue.stop(); + } + + public boolean render(MapTile tile) { + return tile.getMap().render(tile, getTileFile(tile)); + } + + + private HashMap worldTileDirectories = new HashMap(); + private File getTileFile(MapTile tile) { + World world = tile.getWorld(); + File worldTileDirectory = worldTileDirectories.get(world); + if (worldTileDirectory == null) { + worldTileDirectory = new File(DynmapPlugin.tilesDirectory, tile.getWorld().getName()); + worldTileDirectory.mkdirs(); + worldTileDirectories.put(world, worldTileDirectory); + } + return new File(worldTileDirectory, tile.getFilename()); } } diff --git a/src/main/java/org/dynmap/MapTile.java b/src/main/java/org/dynmap/MapTile.java index 16c894fa..25bb2c77 100644 --- a/src/main/java/org/dynmap/MapTile.java +++ b/src/main/java/org/dynmap/MapTile.java @@ -1,15 +1,28 @@ package org.dynmap; +import org.bukkit.World; + public abstract class MapTile { + private World world; private MapType map; + public World getWorld() { + return world; + } + public MapType getMap() { return map; } - public abstract String getName(); + public abstract String getFilename(); - public MapTile(MapType map) { + public MapTile(World world, MapType map) { + this.world = world; this.map = map; } + + @Override + public int hashCode() { + return getFilename().hashCode() ^ getWorld().hashCode(); + } } diff --git a/src/main/java/org/dynmap/MapType.java b/src/main/java/org/dynmap/MapType.java index e80034b2..64ff0f24 100644 --- a/src/main/java/org/dynmap/MapType.java +++ b/src/main/java/org/dynmap/MapType.java @@ -1,41 +1,17 @@ package org.dynmap; +import java.io.File; + import org.bukkit.Location; -import org.bukkit.World; -import org.dynmap.debug.Debugger; public abstract class MapType { - private MapManager manager; - - public MapManager getMapManager() { - return manager; - } - - private World world; - - public World getWorld() { - return world; - } - - private Debugger debugger; - - public Debugger getDebugger() { - return debugger; - } - - public MapType(MapManager manager, World world, Debugger debugger) { - this.manager = manager; - this.world = world; - this.debugger = debugger; - } - + public Event onTileInvalidated = new Event(); + public abstract MapTile[] getTiles(Location l); public abstract MapTile[] getAdjecentTiles(MapTile tile); public abstract DynmapChunk[] getRequiredChunks(MapTile tile); - public abstract boolean render(MapTile tile); - - public abstract boolean isRendered(MapTile tile); + public abstract boolean render(MapTile tile, File outputFile); } diff --git a/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java b/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java index 56b2d587..30c67553 100644 --- a/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java +++ b/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java @@ -1,8 +1,6 @@ package org.dynmap.debug; import java.util.HashSet; -import java.util.logging.Level; -import java.util.logging.Logger; import org.bukkit.ChatColor; import org.bukkit.entity.Player; @@ -11,14 +9,9 @@ import org.bukkit.event.Event.Priority; import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerEvent; import org.bukkit.event.player.PlayerListener; -import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; public class BukkitPlayerDebugger implements Debugger { - protected static final Logger log = Logger.getLogger("Minecraft"); - - private boolean isLogging = false; - private JavaPlugin plugin; private HashSet debugees = new HashSet(); private String debugCommand; @@ -28,10 +21,10 @@ public class BukkitPlayerDebugger implements Debugger { public BukkitPlayerDebugger(JavaPlugin plugin) { this.plugin = plugin; - PluginDescriptionFile pdfFile = plugin.getDescription(); - debugCommand = "/debug_" + pdfFile.getName(); - undebugCommand = "/undebug_" + pdfFile.getName(); - prepend = pdfFile.getName() + ": "; + String name = "dynmap"; + debugCommand = "/debug_" + name; + undebugCommand = "/undebug_" + name; + prepend = name + ": "; } public synchronized void enable() { @@ -63,19 +56,15 @@ public class BukkitPlayerDebugger implements Debugger { public synchronized void debug(String message) { sendToDebuggees(message); - if (isLogging) - log.info(prepend + message); } public synchronized void error(String message) { sendToDebuggees(prepend + ChatColor.RED + message); - log.log(Level.SEVERE, prepend + message); } public synchronized void error(String message, Throwable thrown) { sendToDebuggees(prepend + ChatColor.RED + message); sendToDebuggees(thrown.toString()); - log.log(Level.SEVERE, prepend + message); } protected class CommandListener extends PlayerListener { diff --git a/src/main/java/org/dynmap/debug/Debug.java b/src/main/java/org/dynmap/debug/Debug.java new file mode 100644 index 00000000..5de813ad --- /dev/null +++ b/src/main/java/org/dynmap/debug/Debug.java @@ -0,0 +1,32 @@ +package org.dynmap.debug; + +import java.util.LinkedList; +import java.util.List; + +public class Debug { + private static List debuggers = new LinkedList(); + + public synchronized static void addDebugger(Debugger d) { + debuggers.add(d); + } + + public synchronized static void removeDebugger(Debugger d) { + debuggers.remove(d); + } + + public synchronized static void clearDebuggers() { + debuggers.clear(); + } + + public synchronized static void debug(String message) { + for(Debugger d : debuggers) d.debug(message); + } + + public synchronized static void error(String message) { + for(Debugger d : debuggers) d.error(message); + } + + public synchronized static void error(String message, Throwable thrown) { + for(Debugger d : debuggers) d.error(message, thrown); + } +} diff --git a/src/main/java/org/dynmap/debug/LogDebugger.java b/src/main/java/org/dynmap/debug/LogDebugger.java new file mode 100644 index 00000000..ec159c2e --- /dev/null +++ b/src/main/java/org/dynmap/debug/LogDebugger.java @@ -0,0 +1,25 @@ +package org.dynmap.debug; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class LogDebugger implements Debugger { + protected static final Logger log = Logger.getLogger("Minecraft"); + private static String prepend = "dynmap: "; + + @Override + public void debug(String message) { + log.info(prepend + message); + } + + @Override + public void error(String message) { + log.log(Level.SEVERE, prepend + message); + } + + @Override + public void error(String message, Throwable thrown) { + log.log(Level.SEVERE, prepend + message); + } + +} diff --git a/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java b/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java index 565a4c2d..afdb1db7 100644 --- a/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/CaveTileRenderer.java @@ -4,12 +4,11 @@ import java.awt.Color; import java.util.Map; import org.bukkit.World; -import org.dynmap.debug.Debugger; public class CaveTileRenderer extends DefaultTileRenderer { - public CaveTileRenderer(Debugger debugger, Map configuration) { - super(debugger, configuration); + public CaveTileRenderer(Map configuration) { + super(configuration); } @Override diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index 06bdc0d5..738be2dc 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -10,24 +10,23 @@ import java.util.Map; import javax.imageio.ImageIO; import org.bukkit.World; -import org.dynmap.debug.Debugger; +import org.dynmap.debug.Debug; public class DefaultTileRenderer implements MapTileRenderer { protected static Color translucent = new Color(0, 0, 0, 0); private String name; - protected Debugger debugger; + @Override public String getName() { return name; } - public DefaultTileRenderer(Debugger debugger, Map configuration) { - this.debugger = debugger; + public DefaultTileRenderer(Map configuration) { name = (String) configuration.get("prefix"); } - public boolean render(KzedMapTile tile, String path) { - World world = tile.getMap().getWorld(); + public boolean render(KzedMapTile tile, File outputFile) { + World world = tile.getWorld(); BufferedImage im = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); WritableRaster r = im.getRaster(); @@ -92,9 +91,11 @@ public class DefaultTileRenderer implements MapTileRenderer { } /* save the generated tile */ - saveTile(tile, im, path); + saveImage(im, outputFile); im.flush(); - ((KzedMap) tile.getMap()).invalidateTile(new KzedZoomedMapTile((KzedMap) tile.getMap(), tile)); + + tile.file = outputFile; + ((KzedMap) tile.getMap()).invalidateTile(new KzedZoomedMapTile(world, (KzedMap) tile.getMap(), tile)); return !isempty; } @@ -154,23 +155,15 @@ public class DefaultTileRenderer implements MapTileRenderer { } /* save rendered tile, update zoom-out tile */ - public void saveTile(KzedMapTile tile, BufferedImage im, String path) { - String tilePath = getPath(tile, path); - - debugger.debug("saving tile " + tilePath); - + public void saveImage(BufferedImage im, File outputFile) { + Debug.debug("saving image " + outputFile.getPath()); /* save image */ try { - File file = new File(tilePath); - ImageIO.write(im, "png", file); + ImageIO.write(im, "png", outputFile); } catch (IOException e) { - debugger.error("Failed to save tile: " + tilePath, e); + Debug.error("Failed to save image: " + outputFile.getPath(), e); } catch (java.lang.NullPointerException e) { - debugger.error("Failed to save tile (NullPointerException): " + tilePath, e); + Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e); } } - - public static String getPath(KzedMapTile tile, String outputPath) { - return new File(new File(outputPath), tile.getName() + ".png").getPath(); - } } diff --git a/src/main/java/org/dynmap/kzedmap/KzedMap.java b/src/main/java/org/dynmap/kzedmap/KzedMap.java index 155f0790..4807671f 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMap.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMap.java @@ -18,6 +18,7 @@ import org.dynmap.DynmapChunk; import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; +import org.dynmap.debug.Debug; import org.dynmap.debug.Debugger; public class KzedMap extends MapType { @@ -43,14 +44,13 @@ public class KzedMap extends MapType { MapTileRenderer[] renderers; ZoomedTileRenderer zoomrenderer; - public KzedMap(MapManager manager, World world, Debugger debugger, Map configuration) { - super(manager, world, debugger); + public KzedMap(Map configuration) { if (colors == null) { colors = loadColorSet("colors.txt"); } renderers = loadRenderers(configuration); - zoomrenderer = new ZoomedTileRenderer(debugger, configuration); + zoomrenderer = new ZoomedTileRenderer(configuration); } private MapTileRenderer[] loadRenderers(Map configuration) { @@ -63,11 +63,12 @@ public class KzedMap extends MapType { String typeName = (String) configuredRenderer.get("class"); log.info("Loading renderer '" + typeName.toString() + "'..."); Class mapTypeClass = Class.forName(typeName); - Constructor constructor = mapTypeClass.getConstructor(Debugger.class, Map.class); - MapTileRenderer mapTileRenderer = (MapTileRenderer) constructor.newInstance(getDebugger(), configuredRenderer); + Constructor constructor = mapTypeClass.getConstructor(Map.class); + MapTileRenderer mapTileRenderer = (MapTileRenderer) constructor.newInstance(configuredRenderer); renderers.add(mapTileRenderer); } catch (Exception e) { - getDebugger().error("Error loading renderer", e); + Debug.error("Error loading renderer", e); + e.printStackTrace(); } } MapTileRenderer[] result = new MapTileRenderer[renderers.size()]; @@ -77,6 +78,8 @@ public class KzedMap extends MapType { @Override public MapTile[] getTiles(Location l) { + World world = l.getWorld(); + int x = l.getBlockX(); int y = l.getBlockY(); int z = l.getBlockZ(); @@ -92,7 +95,7 @@ public class KzedMap extends MapType { ArrayList tiles = new ArrayList(); - addTile(tiles, tx, ty); + addTile(tiles, world, tx, ty); boolean ledge = tilex(px - 4) != tx; boolean tedge = tiley(py - 4) != ty; @@ -100,22 +103,22 @@ public class KzedMap extends MapType { boolean bedge = tiley(py + 4) != ty; if (ledge) - addTile(tiles, tx - tileWidth, ty); + addTile(tiles, world, tx - tileWidth, ty); if (redge) - addTile(tiles, tx + tileWidth, ty); + addTile(tiles, world, tx + tileWidth, ty); if (tedge) - addTile(tiles, tx, ty - tileHeight); + addTile(tiles, world, tx, ty - tileHeight); if (bedge) - addTile(tiles, tx, ty + tileHeight); + addTile(tiles, world, tx, ty + tileHeight); if (ledge && tedge) - addTile(tiles, tx - tileWidth, ty - tileHeight); + addTile(tiles, world, tx - tileWidth, ty - tileHeight); if (ledge && bedge) - addTile(tiles, tx - tileWidth, ty + tileHeight); + addTile(tiles, world, tx - tileWidth, ty + tileHeight); if (redge && tedge) - addTile(tiles, tx + tileWidth, ty - tileHeight); + addTile(tiles, world, tx + tileWidth, ty - tileHeight); if (redge && bedge) - addTile(tiles, tx + tileWidth, ty + tileHeight); + addTile(tiles, world, tx + tileWidth, ty + tileHeight); MapTile[] result = new MapTile[tiles.size()]; tiles.toArray(result); @@ -126,24 +129,25 @@ public class KzedMap extends MapType { public MapTile[] getAdjecentTiles(MapTile tile) { if (tile instanceof KzedMapTile) { KzedMapTile t = (KzedMapTile) tile; + World world = tile.getWorld(); MapTileRenderer renderer = t.renderer; return new MapTile[] { - new KzedMapTile(this, renderer, t.px - tileWidth, t.py), - new KzedMapTile(this, renderer, t.px + tileWidth, t.py), - new KzedMapTile(this, renderer, t.px, t.py - tileHeight), - new KzedMapTile(this, renderer, t.px, t.py + tileHeight) }; + new KzedMapTile(world, this, renderer, t.px - tileWidth, t.py), + new KzedMapTile(world, this, renderer, t.px + tileWidth, t.py), + new KzedMapTile(world, this, renderer, t.px, t.py - tileHeight), + new KzedMapTile(world, this, renderer, t.px, t.py + tileHeight) }; } return new MapTile[0]; } - public void addTile(ArrayList tiles, int px, int py) { + public void addTile(ArrayList tiles, World world, int px, int py) { for (int i = 0; i < renderers.length; i++) { - tiles.add(new KzedMapTile(this, renderers[i], px, py)); + tiles.add(new KzedMapTile(world, this, renderers[i], px, py)); } } public void invalidateTile(MapTile tile) { - getMapManager().invalidateTile(tile); + onTileInvalidated.trigger(tile); } @Override @@ -174,21 +178,12 @@ public class KzedMap extends MapType { } @Override - public boolean render(MapTile tile) { + public boolean render(MapTile tile, File outputFile) { if (tile instanceof KzedZoomedMapTile) { - zoomrenderer.render((KzedZoomedMapTile) tile, getMapManager().tileDirectory.getAbsolutePath()); + zoomrenderer.render((KzedZoomedMapTile) tile, outputFile); return true; } else if (tile instanceof KzedMapTile) { - return ((KzedMapTile) tile).renderer.render((KzedMapTile) tile, getMapManager().tileDirectory.getAbsolutePath()); - } - return false; - } - - @Override - public boolean isRendered(MapTile tile) { - if (tile instanceof KzedMapTile) { - File tileFile = new File(DefaultTileRenderer.getPath((KzedMapTile) tile, getMapManager().tileDirectory.getAbsolutePath())); - return tileFile.exists(); + return ((KzedMapTile) tile).renderer.render((KzedMapTile) tile, outputFile); } return false; } @@ -235,10 +230,10 @@ public class KzedMap extends MapType { /* load colorset */ File cfile = new File(colorsetpath); if (cfile.isFile()) { - getDebugger().debug("Loading colors from '" + colorsetpath + "'..."); + Debug.debug("Loading colors from '" + colorsetpath + "'..."); stream = new FileInputStream(cfile); } else { - getDebugger().debug("Loading colors from jar..."); + Debug.debug("Loading colors from jar..."); stream = KzedMap.class.getResourceAsStream("/colors.txt"); } @@ -270,7 +265,7 @@ public class KzedMap extends MapType { } scanner.close(); } catch (Exception e) { - getDebugger().error("Could not load colors", e); + Debug.error("Could not load colors", e); return null; } return colors; diff --git a/src/main/java/org/dynmap/kzedmap/KzedMapTile.java b/src/main/java/org/dynmap/kzedmap/KzedMapTile.java index 6b6da8c3..a65d60ad 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMapTile.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMapTile.java @@ -1,25 +1,20 @@ package org.dynmap.kzedmap; -import java.util.logging.Logger; - +import java.io.File; +import org.bukkit.World; import org.dynmap.MapTile; public class KzedMapTile extends MapTile { - protected static final Logger log = Logger.getLogger("Minecraft"); - public KzedMap map; - public MapTileRenderer renderer; - - /* projection position */ public int px, py; - - /* minecraft space origin */ public int mx, my, mz; + + // Hack. + public File file = null; - /* create new MapTile */ - public KzedMapTile(KzedMap map, MapTileRenderer renderer, int px, int py) { - super(map); + public KzedMapTile(World world, KzedMap map, MapTileRenderer renderer, int px, int py) { + super(world, map); this.map = map; this.renderer = renderer; this.px = px; @@ -31,12 +26,13 @@ public class KzedMapTile extends MapTile { } @Override - public String getName() { - return renderer.getName() + "_" + px + "_" + py; + public String getFilename() { + return renderer.getName() + "_" + px + "_" + py + ".png"; } + @Override public int hashCode() { - return getName().hashCode(); + return getFilename().hashCode() ^ getWorld().hashCode(); } @Override @@ -48,11 +44,10 @@ public class KzedMapTile extends MapTile { } public boolean equals(KzedMapTile o) { - return o.getName().equals(getName()); + return o.px == px && o.py == py && o.getWorld().equals(getWorld()); } - /* return a simple string representation... */ public String toString() { - return getName(); + return getWorld().getName() + ":" + getFilename(); } } diff --git a/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java b/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java index 58238962..abfa2b00 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java +++ b/src/main/java/org/dynmap/kzedmap/KzedZoomedMapTile.java @@ -2,18 +2,19 @@ package org.dynmap.kzedmap; import java.awt.image.BufferedImage; +import org.bukkit.World; import org.dynmap.MapTile; public class KzedZoomedMapTile extends MapTile { @Override - public String getName() { - return "z" + originalTile.renderer.getName() + "_" + getTileX() + "_" + getTileY(); + public String getFilename() { + return "z" + originalTile.renderer.getName() + "_" + getTileX() + "_" + getTileY() + ".png"; } public KzedMapTile originalTile; - public KzedZoomedMapTile(KzedMap map, KzedMapTile original) { - super(map); + public KzedZoomedMapTile(World world, KzedMap map, KzedMapTile original) { + super(world, map); this.originalTile = original; } @@ -42,7 +43,7 @@ public class KzedZoomedMapTile extends MapTile { @Override public int hashCode() { - return getName().hashCode(); + return getFilename().hashCode() ^ getWorld().hashCode(); } @Override diff --git a/src/main/java/org/dynmap/kzedmap/MapTileRenderer.java b/src/main/java/org/dynmap/kzedmap/MapTileRenderer.java index eb87a5c1..7674990f 100644 --- a/src/main/java/org/dynmap/kzedmap/MapTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/MapTileRenderer.java @@ -1,7 +1,9 @@ package org.dynmap.kzedmap; +import java.io.File; + public interface MapTileRenderer { String getName(); - boolean render(KzedMapTile tile, String path); + boolean render(KzedMapTile tile, File outputFile); } diff --git a/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java b/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java index 793624a6..094cb949 100644 --- a/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/ZoomedTileRenderer.java @@ -6,19 +6,14 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Map; - import javax.imageio.ImageIO; - -import org.dynmap.debug.Debugger; +import org.dynmap.debug.Debug; public class ZoomedTileRenderer { - protected Debugger debugger; - - public ZoomedTileRenderer(Debugger debugger, Map configuration) { - this.debugger = debugger; + public ZoomedTileRenderer(Map configuration) { } - public void render(KzedZoomedMapTile zt, String outputPath) { + public void render(KzedZoomedMapTile zt, File outputPath) { KzedMapTile originalTile = zt.originalTile; int px = originalTile.px; int py = originalTile.py; @@ -27,17 +22,17 @@ public class ZoomedTileRenderer { BufferedImage image = null; try { - image = ImageIO.read(new File(new File(outputPath), originalTile.getName() + ".png")); + image = ImageIO.read(originalTile.file); } catch (IOException e) { } if (image == null) { - debugger.debug("Could not load original tile, won't render zoom-out tile."); + Debug.debug("Could not load original tile, won't render zoom-out tile."); return; } BufferedImage zIm = null; - File zoomFile = new File(new File(outputPath), zt.getName() + ".png"); + File zoomFile = outputPath; try { zIm = ImageIO.read(zoomFile); } catch (IOException e) { @@ -46,9 +41,9 @@ public class ZoomedTileRenderer { if (zIm == null) { /* create new one */ zIm = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); - debugger.debug("New zoom-out tile created " + zt.getName()); + Debug.debug("New zoom-out tile created " + zt.getFilename()); } else { - debugger.debug("Loaded zoom-out tile from " + zt.getName()); + Debug.debug("Loaded zoom-out tile from " + zt.getFilename()); } /* update zoom-out tile */ @@ -77,11 +72,11 @@ public class ZoomedTileRenderer { /* save zoom-out tile */ try { ImageIO.write(zIm, "png", zoomFile); - debugger.debug("Saved zoom-out tile at " + zoomFile.getName()); + Debug.debug("Saved zoom-out tile at " + zoomFile.getName()); } catch (IOException e) { - debugger.error("Failed to save zoom-out tile: " + zoomFile.getName(), e); + Debug.error("Failed to save zoom-out tile: " + zoomFile.getName(), e); } catch (java.lang.NullPointerException e) { - debugger.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e); + Debug.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e); } zIm.flush(); }