From 403a2acc53fa893bd364654ba4c3b48a942b0b98 Mon Sep 17 00:00:00 2001 From: FrozenCow Date: Thu, 10 Feb 2011 01:20:50 +0100 Subject: [PATCH 01/34] Added default player-faces. --- web/minecraft.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/web/minecraft.js b/web/minecraft.js index 1c193539..976e3dc3 100644 --- a/web/minecraft.js +++ b/web/minecraft.js @@ -16,7 +16,7 @@ function blitImage(ctx, image, sx ,sy, sw, sh, dx, dy, dw, dh) { } } -function createMinecraftHead(player,completed) { +function createMinecraftHead(player,completed,failed) { var skinImage = new Image(); skinImage.onload = function() { var headCanvas = document.createElement('canvas'); @@ -27,6 +27,13 @@ function createMinecraftHead(player,completed) { blitImage(headContext, skinImage, 40,8,8,8, 0,0,8,8); completed(headCanvas); }; + skinImage.onerror = function() { + if (skinImage.src == 'http://www.minecraft.net/img/char.png') { + failed(); + } else { + skinImage.src = 'http://www.minecraft.net/img/char.png'; + } + }; skinImage.src = 'http://www.minecraft.net/skin/' + player + '.png'; } @@ -60,6 +67,8 @@ function getMinecraftHead(player,size,completed) { for(i=0;i Date: Fri, 11 Feb 2011 06:28:17 -0800 Subject: [PATCH 02/34] Changed tilepath to tilespath in configuration. --- configuration.txt | 98 +++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 49 deletions(-) mode change 100755 => 100644 configuration.txt diff --git a/configuration.txt b/configuration.txt old mode 100755 new mode 100644 index 0c880ec7..4c90e367 --- a/configuration.txt +++ b/configuration.txt @@ -1,49 +1,49 @@ -# All paths in this configuration file are relative to Dynmap's data-folder: minecraft_server/plugins/dynmap/ - -# How often a tile gets rendered (in seconds). -renderinterval: 1 - -# The path where the tile-files are placed. -tilepath: web/tiles - -# The path where the web-files are located. -webpath: web - -# The network-interface the webserver will bind to (0.0.0.0 for all interfaces, 127.0.0.1 for only local access). -webserver-bindaddress: 0.0.0.0 - -# The TCP-port the webserver will listen on. -webserver-port: 8123 - -disabledcommands: - - fullrender - -# The maptypes Dynmap will use to render. -maps: - - class: org.dynmap.kzedmap.KzedMap - renderers: - - class: org.dynmap.kzedmap.DefaultTileRenderer - prefix: t - - class: org.dynmap.kzedmap.CaveTileRenderer - prefix: ct - -web: - # Interval the browser should poll for updates. - updaterate: 2000 - - showchatballoons: true - showplayerfacesonmap: true - showplayerfacesinmenu: true - focuschatballoons: false - - # The name of the map shown when opening Dynmap's page (must be in menu). - defaultmap: defaultmap - - # The maps shown in the menu. - shownmaps: - - type: KzedMapType - name: defaultmap - prefix: t - - type: KzedMapType - name: cavemap - prefix: ct +# All paths in this configuration file are relative to Dynmap's data-folder: minecraft_server/plugins/dynmap/ + +# How often a tile gets rendered (in seconds). +renderinterval: 1 + +# The path where the tile-files are placed. +tilespath: web/tiles + +# The path where the web-files are located. +webpath: web + +# The network-interface the webserver will bind to (0.0.0.0 for all interfaces, 127.0.0.1 for only local access). +webserver-bindaddress: 0.0.0.0 + +# The TCP-port the webserver will listen on. +webserver-port: 8123 + +disabledcommands: + - fullrender + +# The maptypes Dynmap will use to render. +maps: + - class: org.dynmap.kzedmap.KzedMap + renderers: + - class: org.dynmap.kzedmap.DefaultTileRenderer + prefix: t + - class: org.dynmap.kzedmap.CaveTileRenderer + prefix: ct + +web: + # Interval the browser should poll for updates. + updaterate: 2000 + + showchatballoons: true + showplayerfacesonmap: true + showplayerfacesinmenu: true + focuschatballoons: false + + # The name of the map shown when opening Dynmap's page (must be in menu). + defaultmap: defaultmap + + # The maps shown in the menu. + shownmaps: + - type: KzedMapType + name: defaultmap + prefix: t + - type: KzedMapType + name: cavemap + prefix: ct From 5b0171c4599434493e5c66727d42fe088941450e Mon Sep 17 00:00:00 2001 From: FrozenCow Date: Sat, 12 Feb 2011 23:45:33 +0100 Subject: [PATCH 03/34] Server-side multiworld support with several improvements overal. --- .../java/org/dynmap/AsynchronousQueue.java | 108 ++++++++++ .../java/org/dynmap/DynmapBlockListener.java | 4 +- .../java/org/dynmap/DynmapPlayerListener.java | 2 +- src/main/java/org/dynmap/DynmapPlugin.java | 37 +++- src/main/java/org/dynmap/Event.java | 26 +++ src/main/java/org/dynmap/Handler.java | 5 + src/main/java/org/dynmap/MapLocation.java | 6 - src/main/java/org/dynmap/MapManager.java | 197 ++++++------------ src/main/java/org/dynmap/MapTile.java | 17 +- src/main/java/org/dynmap/MapType.java | 34 +-- .../dynmap/debug/BukkitPlayerDebugger.java | 19 +- src/main/java/org/dynmap/debug/Debug.java | 32 +++ .../java/org/dynmap/debug/LogDebugger.java | 25 +++ .../org/dynmap/kzedmap/CaveTileRenderer.java | 5 +- .../dynmap/kzedmap/DefaultTileRenderer.java | 35 ++-- src/main/java/org/dynmap/kzedmap/KzedMap.java | 69 +++--- .../java/org/dynmap/kzedmap/KzedMapTile.java | 31 ++- .../org/dynmap/kzedmap/KzedZoomedMapTile.java | 11 +- .../org/dynmap/kzedmap/MapTileRenderer.java | 4 +- .../dynmap/kzedmap/ZoomedTileRenderer.java | 27 +-- 20 files changed, 398 insertions(+), 296 deletions(-) create mode 100644 src/main/java/org/dynmap/AsynchronousQueue.java create mode 100644 src/main/java/org/dynmap/Event.java create mode 100644 src/main/java/org/dynmap/Handler.java delete mode 100644 src/main/java/org/dynmap/MapLocation.java create mode 100644 src/main/java/org/dynmap/debug/Debug.java create mode 100644 src/main/java/org/dynmap/debug/LogDebugger.java 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(); } From 100f3e05908ad80a3f426c6e729d09d0440189c6 Mon Sep 17 00:00:00 2001 From: FrozenCow Date: Sun, 13 Feb 2011 01:19:47 +0100 Subject: [PATCH 04/34] Added multiworld update support along with client-side support. --- configuration.txt | 9 ++++ .../java/org/dynmap/DynmapPlayerListener.java | 2 +- src/main/java/org/dynmap/MapManager.java | 38 ++++++++++++-- src/main/java/org/dynmap/PlayerList.java | 16 ++++++ src/main/java/org/dynmap/UpdateQueue.java | 4 +- src/main/java/org/dynmap/kzedmap/KzedMap.java | 2 - .../web/handlers/ClientUpdateHandler.java | 22 +++++++-- web/map.js | 49 +++++++++++++++++-- 8 files changed, 124 insertions(+), 18 deletions(-) diff --git a/configuration.txt b/configuration.txt index 4c90e367..30e73264 100644 --- a/configuration.txt +++ b/configuration.txt @@ -47,3 +47,12 @@ web: - type: KzedMapType name: cavemap prefix: ct + + # The name of the world shown when opening Dynmap's page. + defaultworld: world + + # The worlds shown in the menu. + shownworlds: + - world + - nether + - world_bad diff --git a/src/main/java/org/dynmap/DynmapPlayerListener.java b/src/main/java/org/dynmap/DynmapPlayerListener.java index d54e2000..7eb9bbc3 100644 --- a/src/main/java/org/dynmap/DynmapPlayerListener.java +++ b/src/main/java/org/dynmap/DynmapPlayerListener.java @@ -66,6 +66,6 @@ public class DynmapPlayerListener extends PlayerListener { * Relevant event details */ public void onPlayerChat(PlayerChatEvent event) { - mgr.updateQueue.pushUpdate(new Client.ChatMessage(event.getPlayer().getName(), event.getMessage())); + mgr.pushUpdate(new Client.ChatMessage(event.getPlayer().getName(), event.getMessage())); } } \ No newline at end of file diff --git a/src/main/java/org/dynmap/MapManager.java b/src/main/java/org/dynmap/MapManager.java index ccfd0fb5..18d8f57d 100644 --- a/src/main/java/org/dynmap/MapManager.java +++ b/src/main/java/org/dynmap/MapManager.java @@ -21,14 +21,16 @@ public class MapManager { private MapType[] mapTypes; public AsynchronousQueue tileQueue; - public UpdateQueue updateQueue; + + public Map worldUpdateQueues = new HashMap(); + public ArrayList worlds = new ArrayList(); + public PlayerList playerList; /* lock for our data structures */ public static final Object lock = new Object(); public MapManager(ConfigurationNode configuration) { - this.updateQueue = new UpdateQueue(); this.tileQueue = new AsynchronousQueue(new Handler() { @Override public void handle(MapTile t) { @@ -81,7 +83,6 @@ public class MapManager { if (render(tile)) { found.remove(tile); rendered.add(tile); - updateQueue.pushUpdate(new Client.Tile(tile.getFilename())); for (MapTile adjTile : map.getAdjecentTiles(tile)) { if (!found.contains(adjTile) && !rendered.contains(adjTile)) { found.add(adjTile); @@ -157,7 +158,9 @@ public class MapManager { } public boolean render(MapTile tile) { - return tile.getMap().render(tile, getTileFile(tile)); + boolean result = tile.getMap().render(tile, getTileFile(tile)); + pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename())); + return result; } @@ -172,4 +175,31 @@ public class MapManager { } return new File(worldTileDirectory, tile.getFilename()); } + + public void pushUpdate(Object update) { + for(int i=0;i visiblePlayers = new ArrayList(); + Player[] onlinePlayers = server.getOnlinePlayers(); + for (int i = 0; i < onlinePlayers.length; i++) { + Player p = onlinePlayers[i]; + if (p.getWorld().getName().equals(worldName) && !hiddenPlayerNames.contains(p.getName())) { + visiblePlayers.add(p); + } + } + Player[] result = new Player[visiblePlayers.size()]; + visiblePlayers.toArray(result); + return result; + } + public Player[] getVisiblePlayers() { ArrayList visiblePlayers = new ArrayList(); Player[] onlinePlayers = server.getOnlinePlayers(); diff --git a/src/main/java/org/dynmap/UpdateQueue.java b/src/main/java/org/dynmap/UpdateQueue.java index bddcb098..24a35eb5 100644 --- a/src/main/java/org/dynmap/UpdateQueue.java +++ b/src/main/java/org/dynmap/UpdateQueue.java @@ -11,7 +11,7 @@ public class UpdateQueue { private static final int maxUpdateAge = 120000; - public void pushUpdate(Object obj) { + public synchronized void pushUpdate(Object obj) { long now = System.currentTimeMillis(); long deadline = now - maxUpdateAge; synchronized (lock) { @@ -27,7 +27,7 @@ public class UpdateQueue { private ArrayList tmpupdates = new ArrayList(); - public Object[] getUpdatedObjects(long since) { + public synchronized Object[] getUpdatedObjects(long since) { long now = System.currentTimeMillis(); long deadline = now - maxUpdateAge; Object[] updates; diff --git a/src/main/java/org/dynmap/kzedmap/KzedMap.java b/src/main/java/org/dynmap/kzedmap/KzedMap.java index 4807671f..ef6d2adb 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMap.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMap.java @@ -15,11 +15,9 @@ import java.util.logging.Logger; import org.bukkit.Location; import org.bukkit.World; 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 { protected static final Logger log = Logger.getLogger("Minecraft"); diff --git a/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java b/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java index c814db9c..6a87f6fc 100644 --- a/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java +++ b/src/main/java/org/dynmap/web/handlers/ClientUpdateHandler.java @@ -2,6 +2,9 @@ package org.dynmap.web.handlers; import java.io.BufferedOutputStream; import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import org.bukkit.World; import org.bukkit.entity.Player; @@ -24,14 +27,24 @@ public class ClientUpdateHandler implements HttpHandler { this.world = world; } + Pattern updatePathPattern = Pattern.compile("world/([a-zA-Z0-9_]+)/([0-9]*)"); @Override public void handle(String path, HttpRequest request, HttpResponse response) throws Exception { + + Matcher match = updatePathPattern.matcher(path); + + if (!match.matches()) + return; + + String worldName = match.group(1); + String timeKey = match.group(2); + long current = System.currentTimeMillis(); - long cutoff = 0; + long since = 0; if (path.length() > 0) { try { - cutoff = Long.parseLong(path); + since = Long.parseLong(timeKey); } catch (NumberFormatException e) { } } @@ -41,14 +54,15 @@ public class ClientUpdateHandler implements HttpHandler { update.servertime = world.getTime() % 24000; - Player[] players = playerList.getVisiblePlayers(); + Player[] players = playerList.getVisiblePlayers(worldName); update.players = new Client.Player[players.length]; for(int i=0;i') + .addClass('worldlist') + .appendTo(sidebar); + + $.each(me.options.shownworlds, function(index, name) { + var worldButton; + $('
') + .addClass('worldrow') + .append(worldButton = $('') + .addClass('worldbutton') + .addClass('world_' + name) + .attr({ + type: 'radio', + name: 'world', + value: name + }) + .attr('checked', me.options.defaultworld == name ? 'checked' : null) + ) + .append($('