Compare commits

..

7 Commits

Author SHA1 Message Date
FrozenCow d566fccb1e Fixed rendering zoomedout tiles. 2011-02-09 13:25:06 +01:00
FrozenCow b2f6ae5132 Disabled fullrender by default. 2011-02-09 01:03:31 +01:00
FrozenCow 5c209c2a5e Renamed y to z in DynmapChunk. 2011-02-09 00:42:16 +01:00
FrozenCow fb1b5df3d0 Made zoomed-rendering make use of existing tile-files instead of keeping those tiles in memory. 2011-02-08 23:38:57 +01:00
FrozenCow 38ee8657e8 Better exception handling. 2011-02-08 20:59:51 +01:00
FrozenCow 89c8d564a4 Made use of newly introduced unloadChunk in BukkitAPI + removal of unstable features. 2011-02-08 20:27:37 +01:00
FrozenCow b31bb14452 disabledcommands can now be empty. 2011-02-07 22:26:55 +01:00
12 changed files with 103 additions and 140 deletions
-5
View File
@@ -3,10 +3,6 @@
# How often a tile gets rendered (in seconds).
renderinterval: 1
# When enabled Dynmap will preload chunks before rendering a tile. This will avoid Dynmap rendering unloaded (=partially blue) tiles.
# This WILL impact memory and diskio.
loadChunks: false
# The path where the tile-files are placed.
tilepath: web/tiles
@@ -21,7 +17,6 @@ webserver-port: 8123
disabledcommands:
- fullrender
- fullrenderasync
# The maptypes Dynmap will use to render.
maps:
+3 -3
View File
@@ -1,10 +1,10 @@
package org.dynmap;
public class DynmapChunk {
public int x, y;
public int x, z;
public DynmapChunk(int x, int y) {
public DynmapChunk(int x, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -21,9 +21,11 @@ public class DynmapPlayerListener extends PlayerListener {
String[] split = event.getMessage().split(" ");
if (split[0].equalsIgnoreCase("/dynmap")) {
if (split.length > 1) {
for(String s : (Iterable<String>)configuration.getProperty("disabledcommands")) {
if (split[1].equals(s)) {
return;
if (configuration.getProperty("disabledcommands") instanceof Iterable<?>) {
for(String s : (Iterable<String>)configuration.getProperty("disabledcommands")) {
if (split[1].equals(s)) {
return;
}
}
}
@@ -52,9 +54,6 @@ public class DynmapPlayerListener extends PlayerListener {
} else if (split[1].equals("fullrender")) {
Player player = event.getPlayer();
mgr.renderFullWorld(player.getLocation());
} else if (split[1].equals("fullrenderasync")) {
Player player = event.getPlayer();
mgr.renderFullWorldAsync(player.getLocation());
}
}
}
+29 -75
View File
@@ -78,27 +78,17 @@ public class MapManager extends Thread {
maps = loadMapTypes(configuration);
}
void renderFullWorldAsync(Location l) {
fullmapTiles.clear();
fullmapTilesRendered.clear();
debugger.debug("Full render starting...");
for (MapType map : maps) {
for (MapTile tile : map.getTiles(l)) {
fullmapTiles.add(tile);
invalidateTile(tile);
}
}
debugger.debug("Full render finished.");
}
void renderFullWorld(Location l) {
debugger.debug("Full render starting...");
for (MapType map : maps) {
int requiredChunkCount = 200;
HashSet<MapTile> found = new HashSet<MapTile>();
HashSet<MapTile> rendered = new HashSet<MapTile>();
LinkedList<MapTile> renderQueue = new LinkedList<MapTile>();
LinkedList<DynmapChunk> loadedChunks = new LinkedList<DynmapChunk>();
for (MapTile tile : map.getTiles(l)) {
if (!(found.contains(tile) || map.isRendered(tile))) {
if (!found.contains(tile)) {
found.add(tile);
renderQueue.add(tile);
}
@@ -106,13 +96,30 @@ public class MapManager extends Thread {
while (!renderQueue.isEmpty()) {
MapTile tile = renderQueue.pollFirst();
loadRequiredChunks(tile);
debugger.debug("renderQueue: " + renderQueue.size() + "/" + found.size());
DynmapChunk[] requiredChunks = tile.getMap().getRequiredChunks(tile);
if (requiredChunks.length > requiredChunkCount)
requiredChunkCount = requiredChunks.length;
// Unload old chunks.
while (loadedChunks.size() >= requiredChunkCount - requiredChunks.length) {
DynmapChunk c = loadedChunks.pollFirst();
world.unloadChunk(c.x, c.z, false, true);
}
// Load the required chunks.
for (DynmapChunk chunk : requiredChunks) {
boolean wasLoaded = world.isChunkLoaded(chunk.x, chunk.z);
world.loadChunk(chunk.x, chunk.z, false);
if (!wasLoaded)
loadedChunks.add(chunk);
}
if (map.render(tile)) {
found.remove(tile);
rendered.add(tile);
updateQueue.pushUpdate(new Client.Tile(tile.getName()));
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
if (!(found.contains(adjTile) || map.isRendered(adjTile))) {
if (!found.contains(adjTile) && !rendered.contains(adjTile)) {
found.add(adjTile);
renderQueue.add(adjTile);
}
@@ -121,62 +128,14 @@ public class MapManager extends Thread {
found.remove(tile);
System.gc();
}
}
debugger.debug("Full render finished.");
}
public HashSet<MapTile> fullmapTiles = new HashSet<MapTile>();
public boolean fullmapRenderStarting = false;
public HashSet<MapTile> fullmapTilesRendered = new HashSet<MapTile>();
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);
// Unload remaining chunks to clean-up.
while (!loadedChunks.isEmpty()) {
DynmapChunk c = loadedChunks.pollFirst();
world.unloadChunk(c.x, c.z, false, true);
}
}
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);
}
debugger.debug("Full render finished.");
}
private MapType[] loadMapTypes(ConfigurationNode configuration) {
@@ -240,15 +199,10 @@ public class MapManager extends Thread {
while (running) {
MapTile t = staleQueue.popStaleTile();
if (t != null) {
loadRequiredChunks(t);
debugger.debug("Rendering tile " + t + "...");
boolean isNonEmptyTile = t.getMap().render(t);
updateQueue.pushUpdate(new Client.Tile(t.getName()));
if (isNonEmptyTile)
handleFullMapRender(t);
try {
Thread.sleep(renderWait);
} catch (InterruptedException e) {
@@ -93,8 +93,8 @@ public class DefaultTileRenderer implements MapTileRenderer {
/* save the generated tile */
saveTile(tile, im, path);
((KzedMap) tile.getMap()).invalidateTile(new KzedZoomedMapTile((KzedMap) tile.getMap(), im, tile));
im.flush();
((KzedMap) tile.getMap()).invalidateTile(new KzedZoomedMapTile((KzedMap) tile.getMap(), tile));
return !isempty;
}
@@ -10,12 +10,10 @@ public class KzedZoomedMapTile extends MapTile {
return "z" + originalTile.renderer.getName() + "_" + getTileX() + "_" + getTileY();
}
public BufferedImage unzoomedImage;
public KzedMapTile originalTile;
public KzedZoomedMapTile(KzedMap map, BufferedImage unzoomedImage, KzedMapTile original) {
public KzedZoomedMapTile(KzedMap map, KzedMapTile original) {
super(map);
this.unzoomedImage = unzoomedImage;
this.originalTile = original;
}
@@ -19,26 +19,36 @@ public class ZoomedTileRenderer {
}
public void render(KzedZoomedMapTile zt, String outputPath) {
KzedMapTile t = zt.originalTile;
String zoomPath = new File(new File(outputPath), zt.getName() + ".png").getPath();
render(t.px, t.py, zt.getTileX(), zt.getTileY(), zt.unzoomedImage, zoomPath);
}
public void render(int px, int py, int zpx, int zpy, BufferedImage image, String zoomPath) {
BufferedImage zIm = null;
debugger.debug("Trying to load zoom-out tile: " + zoomPath);
KzedMapTile originalTile = zt.originalTile;
int px = originalTile.px;
int py = originalTile.py;
int zpx = zt.getTileX();
int zpy = zt.getTileY();
BufferedImage image = null;
try {
File file = new File(zoomPath);
zIm = ImageIO.read(file);
image = ImageIO.read(new File(new File(outputPath), originalTile.getName() + ".png"));
} catch (IOException e) {
}
if (image == null) {
debugger.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");
try {
zIm = ImageIO.read(zoomFile);
} catch (IOException e) {
}
if (zIm == null) {
/* create new one */
zIm = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB);
debugger.debug("New zoom-out tile created " + zoomPath);
debugger.debug("New zoom-out tile created " + zt.getName());
} else {
debugger.debug("Loaded zoom-out tile from " + zoomPath);
debugger.debug("Loaded zoom-out tile from " + zt.getName());
}
/* update zoom-out tile */
@@ -66,13 +76,12 @@ public class ZoomedTileRenderer {
/* save zoom-out tile */
try {
File file = new File(zoomPath);
ImageIO.write(zIm, "png", file);
debugger.debug("Saved zoom-out tile at " + zoomPath);
ImageIO.write(zIm, "png", zoomFile);
debugger.debug("Saved zoom-out tile at " + zoomFile.getName());
} catch (IOException e) {
debugger.error("Failed to save zoom-out tile: " + zoomPath, e);
debugger.error("Failed to save zoom-out tile: " + zoomFile.getName(), e);
} catch (java.lang.NullPointerException e) {
debugger.error("Failed to save zoom-out tile (NullPointerException): " + zoomPath, e);
debugger.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e);
}
zIm.flush();
}
@@ -1,7 +1,6 @@
package org.dynmap.web;
import java.io.IOException;
public interface HttpHandler {
void handle(String path, HttpRequest request, HttpResponse response) throws IOException;
void handle(String path, HttpRequest request, HttpResponse response) throws Exception;
}
@@ -75,7 +75,7 @@ public class HttpServerConnection extends Thread {
public void run() {
try {
socket.setSoTimeout(30000);
socket.setSoTimeout(5000);
HttpRequest request = new HttpRequest();
if (!readRequestHeader(socket.getInputStream(), request)) {
@@ -106,10 +106,13 @@ public class HttpServerConnection extends Thread {
try {
handler.handle(relativePath, request, response);
} catch (IOException e) {
throw e;
} catch (Exception e) {
log.log(Level.SEVERE, "HttpHandler '" + handler + "' has thown an exception", e);
e.printStackTrace();
socket.close();
if (socket != null) {
socket.close();
}
return;
}
@@ -1,7 +1,6 @@
package org.dynmap.web.handlers;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
@@ -16,7 +15,7 @@ public class ClientConfigurationHandler implements HttpHandler {
this.configuration = configuration;
}
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws IOException {
public void handle(String path, HttpRequest request, HttpResponse response) throws Exception {
String s = Json.stringifyJson(configuration);
byte[] bytes = s.getBytes();
@@ -1,7 +1,6 @@
package org.dynmap.web.handlers;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.Date;
import org.bukkit.World;
@@ -26,7 +25,7 @@ public class ClientUpdateHandler implements HttpHandler {
}
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws IOException {
public void handle(String path, HttpRequest request, HttpResponse response) throws Exception {
long current = System.currentTimeMillis();
long cutoff = 0;
@@ -56,30 +56,38 @@ public abstract class FileHandler implements HttpHandler {
}
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws IOException {
path = formatPath(path);
InputStream fileInput = getFileInput(path);
if (fileInput == null) {
response.statusCode = 404;
response.statusMessage = "Not found";
return;
}
String extension = getExtension(path);
String mimeType = getMimeTypeFromExtension(extension);
response.fields.put("Content-Type", mimeType);
response.fields.put("Connection", "close");
OutputStream out = response.getBody();
public void handle(String path, HttpRequest request, HttpResponse response) throws Exception {
InputStream fileInput = null;
try {
int readBytes;
while ((readBytes = fileInput.read(readBuffer)) > 0) {
out.write(readBuffer, 0, readBytes);
path = formatPath(path);
fileInput = getFileInput(path);
if (fileInput == null) {
response.statusCode = 404;
response.statusMessage = "Not found";
return;
}
String extension = getExtension(path);
String mimeType = getMimeTypeFromExtension(extension);
response.fields.put("Content-Type", mimeType);
response.fields.put("Connection", "close");
OutputStream out = response.getBody();
try {
int readBytes;
while ((readBytes = fileInput.read(readBuffer)) > 0) {
out.write(readBuffer, 0, readBytes);
}
} catch (IOException e) {
fileInput.close();
throw e;
}
} catch (IOException e) {
fileInput.close();
} catch (Exception e) {
if (fileInput != null) {
try { fileInput.close(); } catch (IOException ex) { }
}
throw e;
}
fileInput.close();
}
}