From c8cf39a440ba6f73283b9ed4fab91413bcf83b09 Mon Sep 17 00:00:00 2001 From: FrozenCow Date: Sat, 5 Feb 2011 02:01:04 +0100 Subject: [PATCH] Added unstable fullmap rendering. Also... messed up formatting by pressing ctrl+shift+f in eclipse, sigh --- src/main/java/org/dynmap/DynmapChunk.java | 9 + .../java/org/dynmap/DynmapPlayerListener.java | 6 + src/main/java/org/dynmap/MapManager.java | 208 +++++++++++++----- src/main/java/org/dynmap/MapType.java | 3 +- src/main/java/org/dynmap/StaleQueue.java | 4 + .../dynmap/debug/BukkitPlayerDebugger.java | 4 +- .../java/org/dynmap/debug/NullDebugger.java | 1 + src/main/java/org/dynmap/kzedmap/KzedMap.java | 128 +++++------ 8 files changed, 236 insertions(+), 127 deletions(-) create mode 100644 src/main/java/org/dynmap/DynmapChunk.java diff --git a/src/main/java/org/dynmap/DynmapChunk.java b/src/main/java/org/dynmap/DynmapChunk.java new file mode 100644 index 00000000..2b0c49e2 --- /dev/null +++ b/src/main/java/org/dynmap/DynmapChunk.java @@ -0,0 +1,9 @@ +package org.dynmap; + +public class DynmapChunk { + public int x,y; + public DynmapChunk(int x, int y) { + this.x = x; + this.y = y; + } +} diff --git a/src/main/java/org/dynmap/DynmapPlayerListener.java b/src/main/java/org/dynmap/DynmapPlayerListener.java index 54d47913..ab12ed05 100644 --- a/src/main/java/org/dynmap/DynmapPlayerListener.java +++ b/src/main/java/org/dynmap/DynmapPlayerListener.java @@ -34,6 +34,12 @@ public class DynmapPlayerListener extends PlayerListener { } else for (int i=2;i found = new HashSet(); + LinkedList renderQueue = new LinkedList(); + + for(MapTile tile : map.getTiles(l)) { + if(!(found.contains(tile) || map.isRendered(tile))) { + found.add(tile); + renderQueue.add(tile); + } + } + while(!renderQueue.isEmpty()) { + MapTile tile = renderQueue.pollFirst(); + + loadRequiredChunks(tile); + debugger.debug("renderQueue: " + renderQueue.size() + "/" + found.size()); + if(map.render(tile)) { + found.remove(tile); + staleQueue.onTileUpdated(tile); + for(MapTile adjTile : map.getAdjecentTiles(tile)) { + if(!(found.contains(adjTile) || map.isRendered(adjTile))) { + found.add(adjTile); + renderQueue.add(adjTile); + } + } + } + found.remove(tile); + System.gc(); + } + } + debugger.debug("Full render finished."); + } + + public HashSet fullmapTiles = new HashSet(); + public boolean fullmapRenderStarting = false; + public HashSet fullmapTilesRendered = new HashSet(); + + void handleFullMapRender(MapTile tile) { + if(!fullmapTiles.contains(tile)) { + debugger.debug("Non fullmap-render tile: " + tile); + return; + } + fullmapTilesRendered.add(tile); + MapType map = tile.getMap(); + MapTile[] adjecenttiles = map.getAdjecentTiles(tile); + for(int i = 0; i < adjecenttiles.length; i++) { + MapTile adjecentTile = adjecenttiles[i]; + if(!fullmapTiles.contains(adjecentTile)) { + fullmapTiles.add(adjecentTile); + staleQueue.pushStaleTile(adjecentTile); + } + } + debugger.debug("Queue size: " + staleQueue.size() + "+" + fullmapTilesRendered.size() + "/" + fullmapTiles.size()); + } + + private boolean hasEnoughMemory() { + return Runtime.getRuntime().freeMemory() >= 100 * 1024 * 1024; + } + + private void waitForMemory() { + if(!hasEnoughMemory()) { + debugger.debug("Waiting for memory..."); + // Wait until there is at least 50mb of free memory. + do { + System.gc(); + try { + Thread.sleep(500); + } catch(InterruptedException e) { + e.printStackTrace(); + } + } while(!hasEnoughMemory()); + debugger.debug(Runtime.getRuntime().freeMemory() / (1024 * 1024) + "MB of memory free, will continue..."); + } + } + + private void loadRequiredChunks(MapTile tile) { + if(!loadChunks) + return; + waitForMemory(); + + // Actually load the chunks. + for(DynmapChunk chunk : tile.getMap().getRequiredChunks(tile)) { + if(!world.isChunkLoaded(chunk.x, chunk.y)) + world.loadChunk(chunk.x, chunk.y); + } + } + private MapType[] loadMapTypes(ConfigurationNode configuration) { - List configuredMaps = (List)configuration.getProperty("maps"); + List configuredMaps = (List) configuration.getProperty("maps"); ArrayList mapTypes = new ArrayList(); for(Object configuredMapObj : configuredMaps) { try { @SuppressWarnings("unchecked") - Map configuredMap = (Map)configuredMapObj; - String typeName = (String)configuredMap.get("class"); + Map configuredMap = (Map) configuredMapObj; + 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); + MapType mapType = (MapType) constructor.newInstance(this, world, debugger, configuredMap); mapTypes.add(mapType); - } catch (Exception e) { + } catch(Exception e) { debugger.error("Error loading map", e); } } @@ -97,30 +202,28 @@ public class MapManager extends Thread { } /* initialize and start map manager */ - public void startManager() - { + 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!"); - } + 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() - { + public void stopManager() { synchronized(lock) { if(!running) return; - + log.info("Stopping map renderer..."); running = false; - + try { this.join(); } catch(InterruptedException e) { @@ -128,31 +231,24 @@ public class MapManager extends Thread { } } } - + /* the worker/renderer thread */ - public void run() - { + public void run() { try { log.info("Map renderer has started."); - + while(running) { MapTile t = staleQueue.popStaleTile(); if(t != null) { - MapType map = t.getMap(); - World world = map.getWorld(); - - Chunk[] requiredChunks = map.getRequiredChunks(t); - debugger.debug("Loading " + requiredChunks.length + " chunks for tile " + t + "..."); - for (int i=0;i(); } + public int size() { + return staleTilesQueue.size(); + } + /* put a MapTile that needs to be regenerated on the list of stale tiles */ public boolean pushStaleTile(MapTile m) { diff --git a/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java b/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java index 52ae6248..b1b3fadb 100644 --- a/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java +++ b/src/main/java/org/dynmap/debug/BukkitPlayerDebugger.java @@ -68,13 +68,13 @@ public class BukkitPlayerDebugger implements Debugger { public synchronized void error(String message) { sendToDebuggees(prepend + ChatColor.RED + message); - if (isLogging) log.log(Level.SEVERE, prepend + message); + log.log(Level.SEVERE, prepend + message); } public synchronized void error(String message, Throwable thrown) { sendToDebuggees(prepend + ChatColor.RED + message); sendToDebuggees(thrown.toString()); - if (isLogging) log.log(Level.SEVERE, prepend + message); + log.log(Level.SEVERE, prepend + message); } protected class CommandListener extends PlayerListener { diff --git a/src/main/java/org/dynmap/debug/NullDebugger.java b/src/main/java/org/dynmap/debug/NullDebugger.java index 0fea7e7d..061e51f8 100644 --- a/src/main/java/org/dynmap/debug/NullDebugger.java +++ b/src/main/java/org/dynmap/debug/NullDebugger.java @@ -1,6 +1,7 @@ package org.dynmap.debug; public class NullDebugger implements Debugger { + public static final NullDebugger instance = new NullDebugger(); public void debug(String message) { } diff --git a/src/main/java/org/dynmap/kzedmap/KzedMap.java b/src/main/java/org/dynmap/kzedmap/KzedMap.java index 5e2b7b47..48faa5c3 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMap.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMap.java @@ -11,10 +11,9 @@ import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.logging.Logger; - -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; +import org.dynmap.DynmapChunk; import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; @@ -52,17 +51,17 @@ public class KzedMap extends MapType { } private MapTileRenderer[] loadRenderers(Map configuration) { - List configuredRenderers = (List)configuration.get("renderers"); + List configuredRenderers = (List) configuration.get("renderers"); ArrayList renderers = new ArrayList(); - for(Object configuredRendererObj : configuredRenderers) { + for (Object configuredRendererObj : configuredRenderers) { try { @SuppressWarnings("unchecked") - Map configuredRenderer = (Map)configuredRendererObj; - String typeName = (String)configuredRenderer.get("class"); + Map configuredRenderer = (Map) configuredRendererObj; + 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); + MapTileRenderer mapTileRenderer = (MapTileRenderer) constructor.newInstance(getDebugger(), configuredRenderer); renderers.add(mapTileRenderer); } catch (Exception e) { getDebugger().error("Error loading renderer", e); @@ -84,28 +83,28 @@ public class KzedMap extends MapType { int dz = z - anchorz; int px = dx + dz; int py = dx - dz - dy; - + int tx = tilex(px); int ty = tiley(py); - + ArrayList tiles = new ArrayList(); addTile(tiles, tx, ty); - + boolean ledge = tilex(px - 4) != tx; boolean tedge = tiley(py - 4) != ty; boolean redge = tilex(px + 4) != tx; boolean bedge = tiley(py + 4) != ty; - - if(ledge) addTile(tiles, tx - tileWidth, ty); - if(redge) addTile(tiles, tx + tileWidth, ty); - if(tedge) addTile(tiles, tx, ty - tileHeight); - if(bedge) addTile(tiles, tx, ty + tileHeight); - - if(ledge && tedge) addTile(tiles, tx - tileWidth, ty - tileHeight); - if(ledge && bedge) addTile(tiles, tx - tileWidth, ty + tileHeight); - if(redge && tedge) addTile(tiles, tx + tileWidth, ty - tileHeight); - if(redge && bedge) addTile(tiles, tx + tileWidth, ty + tileHeight); + + if (ledge) addTile(tiles, tx - tileWidth, ty); + if (redge) addTile(tiles, tx + tileWidth, ty); + if (tedge) addTile(tiles, tx, ty - tileHeight); + if (bedge) addTile(tiles, tx, ty + tileHeight); + + if (ledge && tedge) addTile(tiles, tx - tileWidth, ty - tileHeight); + if (ledge && bedge) addTile(tiles, tx - tileWidth, ty + tileHeight); + if (redge && tedge) addTile(tiles, tx + tileWidth, ty - tileHeight); + if (redge && bedge) addTile(tiles, tx + tileWidth, ty + tileHeight); MapTile[] result = new MapTile[tiles.size()]; tiles.toArray(result); @@ -115,20 +114,20 @@ public class KzedMap extends MapType { @Override public MapTile[] getAdjecentTiles(MapTile tile) { if (tile instanceof KzedMapTile) { - KzedMapTile t = (KzedMapTile)tile; + KzedMapTile t = (KzedMapTile) tile; 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(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) + }; } return new MapTile[0]; } public void addTile(ArrayList tiles, int px, int py) { - for (int i=0;i chunks = new ArrayList(); - World world = getWorld(); - for(x=x1; x chunks = new ArrayList(); + for (x = x1; x < x2; x += 16) { + for (z = z1; z < z2; z += 16) { + DynmapChunk chunk = new DynmapChunk(x / 16, z / 16); chunks.add(chunk); } } - Chunk[] result = new Chunk[chunks.size()]; + DynmapChunk[] result = new DynmapChunk[chunks.size()]; chunks.toArray(result); return result; } else { - return new Chunk[0]; + return new DynmapChunk[0]; } } @Override public boolean render(MapTile tile) { if (tile instanceof KzedZoomedMapTile) { - zoomrenderer.render((KzedZoomedMapTile)tile, getMapManager().tileDirectory.getAbsolutePath()); + zoomrenderer.render((KzedZoomedMapTile) tile, getMapManager().tileDirectory.getAbsolutePath()); return true; } else if (tile instanceof KzedMapTile) { - return ((KzedMapTile)tile).renderer.render((KzedMapTile)tile, getMapManager().tileDirectory.getAbsolutePath()); + return ((KzedMapTile) tile).renderer.render((KzedMapTile) tile, getMapManager().tileDirectory.getAbsolutePath()); } return false; } @@ -179,45 +177,41 @@ public class KzedMap extends MapType { @Override public boolean isRendered(MapTile tile) { if (tile instanceof KzedMapTile) { - File tileFile = new File(DefaultTileRenderer.getPath((KzedMapTile)tile, getMapManager().tileDirectory.getAbsolutePath())); + File tileFile = new File(DefaultTileRenderer.getPath((KzedMapTile) tile, getMapManager().tileDirectory.getAbsolutePath())); return tileFile.exists(); } return false; } /* tile X for position x */ - static int tilex(int x) - { - if(x < 0) + static int tilex(int x) { + if (x < 0) return x - (tileWidth + (x % tileWidth)); else return x - (x % tileWidth); } - + /* tile Y for position y */ - static int tiley(int y) - { - if(y < 0) + static int tiley(int y) { + if (y < 0) return y - (tileHeight + (y % tileHeight)); else return y - (y % tileHeight); } - + /* zoomed-out tile X for tile position x */ - static int ztilex(int x) - { - if(x < 0) + static int ztilex(int x) { + if (x < 0) return x + x % zTileWidth; else return x - (x % zTileWidth); } - + /* zoomed-out tile Y for tile position y */ - static int ztiley(int y) - { - if(y < 0) + static int ztiley(int y) { + if (y < 0) return y + y % zTileHeight; - //return y - (zTileHeight + (y % zTileHeight)); + //return y - (zTileHeight + (y % zTileHeight)); else return y - (y % zTileHeight); } @@ -404,12 +398,12 @@ public class KzedMap extends MapType { return good; } */ - + public java.util.Map loadColorSet(String colorsetpath) { java.util.Map colors = new HashMap(); - + InputStream stream; - + try { /* load colorset */ File cfile = new File(colorsetpath); @@ -423,32 +417,32 @@ public class KzedMap extends MapType { Scanner scanner = new Scanner(stream); int nc = 0; - while(scanner.hasNextLine()) { + while (scanner.hasNextLine()) { String line = scanner.nextLine(); if (line.startsWith("#") || line.equals("")) { continue; } - + String[] split = line.split("\t"); if (split.length < 17) { continue; } - + Integer id = new Integer(split[0]); - + Color[] c = new Color[4]; - + /* store colors by raycast sequence number */ c[0] = new Color(Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4])); c[3] = new Color(Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8])); c[1] = new Color(Integer.parseInt(split[9]), Integer.parseInt(split[10]), Integer.parseInt(split[11]), Integer.parseInt(split[12])); c[2] = new Color(Integer.parseInt(split[13]), Integer.parseInt(split[14]), Integer.parseInt(split[15]), Integer.parseInt(split[16])); - + colors.put(id, c); nc += 1; } scanner.close(); - } catch(Exception e) { + } catch (Exception e) { getDebugger().error("Could not load colors", e); return null; }