mirror of
https://github.com/encounter/dynmap.git
synced 2026-03-30 11:08:39 -07:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c32aebff9 | |||
| 1102c08b3e | |||
| e6a8e54172 | |||
| e2b55c3b54 | |||
| faceab68f1 | |||
| 2863dd0acc | |||
| 48fea32500 | |||
| f118ada39e | |||
| edf898ae1a | |||
| bf29c09522 |
@@ -106,6 +106,9 @@ webserver-port: 8123
|
||||
# Disables Webserver portion of Dynmap (Advanced users only)
|
||||
disable-webserver: false
|
||||
|
||||
# Enable/disable having the web server allow symbolic links (true=compatible with existing code, false=more secure (default))
|
||||
allow-symlinks: true
|
||||
|
||||
# Period between tile renders for fullrender, in seconds (non-zero to pace fullrenders, lessen CPU load)
|
||||
timesliceinterval: 0.0
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.dynmap</groupId>
|
||||
<artifactId>dynmap</artifactId>
|
||||
<version>0.19</version>
|
||||
<version>0.19.1</version>
|
||||
<name>dynmap</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
@@ -136,10 +136,14 @@ public class DynmapPlugin extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
int port = configuration.getInteger("webserver-port", 8123);
|
||||
|
||||
boolean allow_symlinks = configuration.getBoolean("allow-symlinks", false);
|
||||
if(allow_symlinks)
|
||||
Log.verboseinfo("Web server is permitting symbolic links");
|
||||
else
|
||||
Log.verboseinfo("Web server is not permitting symbolic links");
|
||||
webServer = new HttpServer(bindAddress, port);
|
||||
webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web"))));
|
||||
webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory));
|
||||
webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")), allow_symlinks));
|
||||
webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory, allow_symlinks));
|
||||
webServer.handlers.put("/up/configuration", new ClientConfigurationHandler(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -301,8 +301,9 @@ public class DynmapWorld {
|
||||
im = ImageIO.read(f);
|
||||
} catch (IOException e) {
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
} finally {
|
||||
FileLockManager.releaseReadLock(f);
|
||||
}
|
||||
FileLockManager.releaseReadLock(f);
|
||||
if(im != null) {
|
||||
im.getRGB(0, 0, width, height, argb, 0, width); /* Read data */
|
||||
im.flush();
|
||||
@@ -333,27 +334,30 @@ public class DynmapWorld {
|
||||
}
|
||||
}
|
||||
FileLockManager.getWriteLock(zf);
|
||||
TileHashManager hashman = MapManager.mapman.hashman;
|
||||
long crc = hashman.calculateTileHash(kzIm.argb_buf); /* Get hash of tile */
|
||||
int tilex = ztx/step/2;
|
||||
int tiley = ty/step/2;
|
||||
String key = world.getName()+".z"+pd.zoomprefix+pd.baseprefix;
|
||||
if((!zf.exists()) || (crc != MapManager.mapman.hashman.getImageHashCode(key, null, tilex, tiley))) {
|
||||
try {
|
||||
if(!zf.getParentFile().exists())
|
||||
zf.getParentFile().mkdirs();
|
||||
FileLockManager.imageIOWrite(zIm, "png", zf);
|
||||
Debug.debug("Saved zoom-out tile at " + zf.getPath());
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e);
|
||||
try {
|
||||
TileHashManager hashman = MapManager.mapman.hashman;
|
||||
long crc = hashman.calculateTileHash(kzIm.argb_buf); /* Get hash of tile */
|
||||
int tilex = ztx/step/2;
|
||||
int tiley = ty/step/2;
|
||||
String key = world.getName()+".z"+pd.zoomprefix+pd.baseprefix;
|
||||
if((!zf.exists()) || (crc != MapManager.mapman.hashman.getImageHashCode(key, null, tilex, tiley))) {
|
||||
try {
|
||||
if(!zf.getParentFile().exists())
|
||||
zf.getParentFile().mkdirs();
|
||||
FileLockManager.imageIOWrite(zIm, "png", zf);
|
||||
Debug.debug("Saved zoom-out tile at " + zf.getPath());
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e);
|
||||
}
|
||||
hashman.updateHashCode(key, null, tilex, tiley, crc);
|
||||
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
|
||||
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
|
||||
}
|
||||
hashman.updateHashCode(key, null, tilex, tiley, crc);
|
||||
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
|
||||
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(zf);
|
||||
KzedMap.freeBufferedImage(kzIm);
|
||||
}
|
||||
FileLockManager.releaseWriteLock(zf);
|
||||
KzedMap.freeBufferedImage(kzIm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
@@ -99,29 +100,36 @@ public class MapManager {
|
||||
@Override
|
||||
public void execute(final Runnable r) {
|
||||
final Runnable rr = r;
|
||||
super.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
try {
|
||||
super.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
r.run();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + r);
|
||||
x.printStackTrace();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + r);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (RejectedExecutionException rxe) { /* Pool shutdown - nominal for reload or unload */
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(final Runnable command, long delay, TimeUnit unit) {
|
||||
return super.schedule(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
command.run();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + command);
|
||||
x.printStackTrace();
|
||||
try {
|
||||
return super.schedule(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
command.run();
|
||||
} catch (Exception x) {
|
||||
Log.severe("Exception during render job: " + command);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, delay, unit);
|
||||
}, delay, unit);
|
||||
} catch (RejectedExecutionException rxe) {
|
||||
return null; /* Pool shut down when we reload or unload */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* This always runs on render pool threads - no bukkit calls from here */
|
||||
@@ -137,7 +145,7 @@ public class MapManager {
|
||||
MapTile tile = null;
|
||||
int rendercnt = 0;
|
||||
CommandSender sender;
|
||||
long starttime;
|
||||
long timeaccum;
|
||||
|
||||
/* Full world, all maps render */
|
||||
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender) {
|
||||
@@ -173,7 +181,7 @@ public class MapManager {
|
||||
/* If render queue is empty, start next map */
|
||||
if(renderQueue.isEmpty()) {
|
||||
if(map_index >= 0) { /* Finished a map? */
|
||||
double msecpertile = (double)(tstart - starttime) / (double)((rendercnt>0)?rendercnt:1);
|
||||
double msecpertile = (double)timeaccum / (double)((rendercnt>0)?rendercnt:1);
|
||||
sender.sendMessage("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' of world '" +
|
||||
world.world.getName() + "' completed - " + rendercnt + " tiles rendered (" + String.format("%.2f", msecpertile) + " msec/tile).");
|
||||
}
|
||||
@@ -187,7 +195,6 @@ public class MapManager {
|
||||
return;
|
||||
}
|
||||
map = world.maps.get(map_index);
|
||||
starttime = System.currentTimeMillis();
|
||||
|
||||
/* Now, prime the render queue */
|
||||
for (MapTile mt : map.getTiles(loc)) {
|
||||
@@ -241,8 +248,9 @@ public class MapManager {
|
||||
found.remove(tile);
|
||||
if(!cache.isEmpty()) {
|
||||
rendercnt++;
|
||||
timeaccum += System.currentTimeMillis() - tstart;
|
||||
if((rendercnt % 100) == 0) {
|
||||
double msecpertile = (double)(System.currentTimeMillis() - starttime) / (double)rendercnt;
|
||||
double msecpertile = (double)timeaccum / (double)rendercnt;
|
||||
sender.sendMessage("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' on world '" +
|
||||
w.getName() + "' in progress - " + rendercnt + " tiles rendered (" + String.format("%.2f", msecpertile) + " msec/tile).");
|
||||
}
|
||||
@@ -496,10 +504,7 @@ public class MapManager {
|
||||
}
|
||||
|
||||
public void stopRendering() {
|
||||
if(renderpool != null) {
|
||||
renderpool.shutdown();
|
||||
renderpool = null;
|
||||
}
|
||||
renderpool.shutdown();
|
||||
tileQueue.stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -271,61 +271,67 @@ public class FlatMap extends MapType {
|
||||
}
|
||||
}
|
||||
/* Test to see if we're unchanged from older tile */
|
||||
FileLockManager.getWriteLock(outputFile);
|
||||
TileHashManager hashman = MapManager.mapman.hashman;
|
||||
long crc = hashman.calculateTileHash(argb_buf);
|
||||
boolean tile_update = false;
|
||||
if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), null, t.x, t.y))) {
|
||||
/* Wrap buffer as buffered image */
|
||||
Debug.debug("saving image " + outputFile.getPath());
|
||||
if(!outputFile.getParentFile().exists())
|
||||
outputFile.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(im.buf_img, "png", outputFile);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + outputFile.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e);
|
||||
FileLockManager.getWriteLock(outputFile);
|
||||
try {
|
||||
if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), null, t.x, t.y))) {
|
||||
/* Wrap buffer as buffered image */
|
||||
Debug.debug("saving image " + outputFile.getPath());
|
||||
if(!outputFile.getParentFile().exists())
|
||||
outputFile.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(im.buf_img, "png", outputFile);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + outputFile.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e);
|
||||
}
|
||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
|
||||
hashman.updateHashCode(tile.getKey(), null, t.x, t.y, crc);
|
||||
tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile);
|
||||
tile_update = true;
|
||||
}
|
||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
|
||||
hashman.updateHashCode(tile.getKey(), null, t.x, t.y, crc);
|
||||
tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile);
|
||||
tile_update = true;
|
||||
else {
|
||||
Debug.debug("skipping image " + outputFile.getPath() + " - hash match");
|
||||
}
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(outputFile);
|
||||
KzedMap.freeBufferedImage(im);
|
||||
}
|
||||
else {
|
||||
Debug.debug("skipping image " + outputFile.getPath() + " - hash match");
|
||||
}
|
||||
KzedMap.freeBufferedImage(im);
|
||||
FileLockManager.releaseWriteLock(outputFile);
|
||||
MapManager.mapman.updateStatistics(tile, null, true, tile_update, !rendered);
|
||||
|
||||
/* If day too, handle it */
|
||||
if(night_and_day) {
|
||||
File dayfile = new File(tile.getDynmapWorld().worldtilepath, tile.getDayFilename());
|
||||
FileLockManager.getWriteLock(dayfile);
|
||||
crc = hashman.calculateTileHash(argb_buf_day);
|
||||
if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), "day", t.x, t.y))) {
|
||||
Debug.debug("saving image " + dayfile.getPath());
|
||||
if(!dayfile.getParentFile().exists())
|
||||
dayfile.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(im_day.buf_img, "png", dayfile);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + dayfile.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + dayfile.getPath(), e);
|
||||
FileLockManager.getWriteLock(dayfile);
|
||||
try {
|
||||
if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), "day", t.x, t.y))) {
|
||||
Debug.debug("saving image " + dayfile.getPath());
|
||||
if(!dayfile.getParentFile().exists())
|
||||
dayfile.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(im_day.buf_img, "png", dayfile);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + dayfile.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + dayfile.getPath(), e);
|
||||
}
|
||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getDayFilename()));
|
||||
hashman.updateHashCode(tile.getKey(), "day", t.x, t.y, crc);
|
||||
tile.getDynmapWorld().enqueueZoomOutUpdate(dayfile);
|
||||
tile_update = true;
|
||||
}
|
||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getDayFilename()));
|
||||
hashman.updateHashCode(tile.getKey(), "day", t.x, t.y, crc);
|
||||
tile.getDynmapWorld().enqueueZoomOutUpdate(dayfile);
|
||||
tile_update = true;
|
||||
else {
|
||||
Debug.debug("skipping image " + dayfile.getPath() + " - hash match");
|
||||
tile_update = false;
|
||||
}
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(dayfile);
|
||||
KzedMap.freeBufferedImage(im_day);
|
||||
}
|
||||
else {
|
||||
Debug.debug("skipping image " + dayfile.getPath() + " - hash match");
|
||||
tile_update = false;
|
||||
}
|
||||
KzedMap.freeBufferedImage(im_day);
|
||||
FileLockManager.releaseWriteLock(dayfile);
|
||||
MapManager.mapman.updateStatistics(tile, "day", true, tile_update, !rendered);
|
||||
}
|
||||
|
||||
|
||||
@@ -256,29 +256,32 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
||||
int oy = (mtile.py == zmtile.getTileY())?0:KzedMap.tileHeight/2;
|
||||
|
||||
/* Test to see if we're unchanged from older tile */
|
||||
FileLockManager.getWriteLock(fname);
|
||||
TileHashManager hashman = MapManager.mapman.hashman;
|
||||
long crc = hashman.calculateTileHash(img.argb_buf);
|
||||
boolean updated_fname = false;
|
||||
int tx = mtile.px/KzedMap.tileWidth;
|
||||
int ty = mtile.py/KzedMap.tileHeight;
|
||||
if((!fname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), null, tx, ty))) {
|
||||
Debug.debug("saving image " + fname.getPath());
|
||||
if(!fname.getParentFile().exists())
|
||||
fname.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(img.buf_img, "png", fname);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + fname.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e);
|
||||
FileLockManager.getWriteLock(fname);
|
||||
try {
|
||||
if((!fname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), null, tx, ty))) {
|
||||
Debug.debug("saving image " + fname.getPath());
|
||||
if(!fname.getParentFile().exists())
|
||||
fname.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(img.buf_img, "png", fname);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + fname.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e);
|
||||
}
|
||||
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getFilename()));
|
||||
hashman.updateHashCode(mtile.getKey(), null, tx, ty, crc);
|
||||
updated_fname = true;
|
||||
}
|
||||
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getFilename()));
|
||||
hashman.updateHashCode(mtile.getKey(), null, tx, ty, crc);
|
||||
updated_fname = true;
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(fname);
|
||||
KzedMap.freeBufferedImage(img);
|
||||
}
|
||||
KzedMap.freeBufferedImage(img);
|
||||
FileLockManager.releaseWriteLock(fname);
|
||||
MapManager.mapman.updateStatistics(mtile, null, true, updated_fname, !rendered);
|
||||
|
||||
mtile.file = fname;
|
||||
@@ -287,25 +290,28 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
||||
|
||||
File dfname = new File(mtile.getDynmapWorld().worldtilepath, mtile.getDayFilename());
|
||||
if(img_day != null) {
|
||||
FileLockManager.getWriteLock(dfname);
|
||||
crc = hashman.calculateTileHash(img.argb_buf);
|
||||
if((!dfname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), "day", tx, ty))) {
|
||||
Debug.debug("saving image " + dfname.getPath());
|
||||
if(!dfname.getParentFile().exists())
|
||||
dfname.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(img_day.buf_img, "png", dfname);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + dfname.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + dfname.getPath(), e);
|
||||
FileLockManager.getWriteLock(dfname);
|
||||
try {
|
||||
if((!dfname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), "day", tx, ty))) {
|
||||
Debug.debug("saving image " + dfname.getPath());
|
||||
if(!dfname.getParentFile().exists())
|
||||
dfname.getParentFile().mkdirs();
|
||||
try {
|
||||
FileLockManager.imageIOWrite(img_day.buf_img, "png", dfname);
|
||||
} catch (IOException e) {
|
||||
Debug.error("Failed to save image: " + dfname.getPath(), e);
|
||||
} catch (java.lang.NullPointerException e) {
|
||||
Debug.error("Failed to save image (NullPointerException): " + dfname.getPath(), e);
|
||||
}
|
||||
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getDayFilename()));
|
||||
hashman.updateHashCode(mtile.getKey(), "day", tx, ty, crc);
|
||||
updated_dfname = true;
|
||||
}
|
||||
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getDayFilename()));
|
||||
hashman.updateHashCode(mtile.getKey(), "day", tx, ty, crc);
|
||||
updated_dfname = true;
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(dfname);
|
||||
KzedMap.freeBufferedImage(img_day);
|
||||
}
|
||||
KzedMap.freeBufferedImage(img_day);
|
||||
FileLockManager.releaseWriteLock(dfname);
|
||||
MapManager.mapman.updateStatistics(mtile, "day", true, updated_dfname, !rendered);
|
||||
}
|
||||
|
||||
@@ -313,30 +319,36 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
||||
// make the zoomed tile here
|
||||
boolean ztile_updated = false;
|
||||
FileLockManager.getWriteLock(zoomFile);
|
||||
if(updated_fname || (!zoomFile.exists())) {
|
||||
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
|
||||
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
||||
try {
|
||||
if(updated_fname || (!zoomFile.exists())) {
|
||||
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
|
||||
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
||||
new Client.Tile(zmtile.getFilename()));
|
||||
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile);
|
||||
ztile_updated = true;
|
||||
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile);
|
||||
ztile_updated = true;
|
||||
}
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(zoomFile);
|
||||
KzedMap.freeBufferedImage(zimg);
|
||||
}
|
||||
KzedMap.freeBufferedImage(zimg);
|
||||
FileLockManager.releaseWriteLock(zoomFile);
|
||||
MapManager.mapman.updateStatistics(zmtile, null, true, ztile_updated, !rendered);
|
||||
|
||||
if(zimg_day != null) {
|
||||
File zoomFile_day = new File(zmtile.getDynmapWorld().worldtilepath, zmtile.getDayFilename());
|
||||
ztile_updated = false;
|
||||
FileLockManager.getWriteLock(zoomFile_day);
|
||||
if(updated_dfname || (!zoomFile_day.exists())) {
|
||||
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
|
||||
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
||||
try {
|
||||
if(updated_dfname || (!zoomFile_day.exists())) {
|
||||
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
|
||||
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
||||
new Client.Tile(zmtile.getDayFilename()));
|
||||
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile_day);
|
||||
ztile_updated = true;
|
||||
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile_day);
|
||||
ztile_updated = true;
|
||||
}
|
||||
} finally {
|
||||
FileLockManager.releaseWriteLock(zoomFile_day);
|
||||
KzedMap.freeBufferedImage(zimg_day);
|
||||
}
|
||||
KzedMap.freeBufferedImage(zimg_day);
|
||||
FileLockManager.releaseWriteLock(zoomFile_day);
|
||||
MapManager.mapman.updateStatistics(zmtile, "day", true, ztile_updated, !rendered);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.World;
|
||||
@@ -67,6 +70,19 @@ public class RegionsComponent extends ClientComponent {
|
||||
|
||||
File webWorldPath = new File(plugin.getWebPath()+"/standalone/", outputFileName);
|
||||
Map<?, ?> regionData = (Map<?, ?>) regionConfig.getProperty(configuration.getString("basenode", "regions"));
|
||||
/* See if we have explicit list of regions to report - limit to this list if we do */
|
||||
List<String> idlist = configuration.getStrings("visibleregions", null);
|
||||
if(idlist != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashSet<String> ids = new HashSet<String>((Collection<? extends String>) regionData.keySet());
|
||||
for(String id : ids) {
|
||||
/* If not in list, remove it */
|
||||
if(!idlist.contains(id)) {
|
||||
regionData.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (webWorldPath.isAbsolute())
|
||||
outputFile = webWorldPath;
|
||||
else {
|
||||
|
||||
@@ -18,7 +18,7 @@ public class FileLockManager {
|
||||
* Get write lock on file - exclusive lock, no other writers or readers
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public static void getWriteLock(File f) {
|
||||
public static boolean getWriteLock(File f) {
|
||||
String fn = f.getPath();
|
||||
synchronized(lock) {
|
||||
boolean got_lock = false;
|
||||
@@ -29,6 +29,7 @@ public class FileLockManager {
|
||||
lock.wait();
|
||||
} catch (InterruptedException ix) {
|
||||
Log.severe("getWriteLock(" + fn + ") interrupted");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -38,6 +39,7 @@ public class FileLockManager {
|
||||
}
|
||||
}
|
||||
//Log.info("getWriteLock(" + f + ")");
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Release write lock
|
||||
@@ -60,10 +62,17 @@ public class FileLockManager {
|
||||
/**
|
||||
* Get read lock on file - multiple readers allowed, blocks writers
|
||||
*/
|
||||
public static void getReadLock(File f) {
|
||||
public static boolean getReadLock(File f) {
|
||||
return getReadLock(f, -1);
|
||||
}
|
||||
/**
|
||||
* Get read lock on file - multiple readers allowed, blocks writers - with timeout (msec)
|
||||
*/
|
||||
public static boolean getReadLock(File f, long timeout) {
|
||||
String fn = f.getPath();
|
||||
synchronized(lock) {
|
||||
boolean got_lock = false;
|
||||
boolean first_wait = true;
|
||||
while(!got_lock) {
|
||||
Integer lockcnt = filelocks.get(fn); /* Get lock count */
|
||||
if(lockcnt == null) {
|
||||
@@ -76,14 +85,23 @@ public class FileLockManager {
|
||||
}
|
||||
else { /* Write lock in place */
|
||||
try {
|
||||
lock.wait();
|
||||
if((timeout > 0) && (!first_wait)) { /* We already waited */
|
||||
return false;
|
||||
}
|
||||
if(timeout < 0)
|
||||
lock.wait();
|
||||
else
|
||||
lock.wait(timeout);
|
||||
first_wait = false;
|
||||
} catch (InterruptedException ix) {
|
||||
Log.severe("getReadLock(" + fn + ") interrupted");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Log.info("getReadLock(" + f + ")");
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Release read lock
|
||||
|
||||
@@ -45,13 +45,15 @@ public class HttpServer extends Thread {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
ServerSocket s = sock;
|
||||
while (listeningThread == Thread.currentThread()) {
|
||||
try {
|
||||
Socket socket = sock.accept();
|
||||
Socket socket = s.accept();
|
||||
HttpServerConnection requestThread = new HttpServerConnection(socket, this);
|
||||
requestThread.start();
|
||||
} catch (IOException e) {
|
||||
Log.info("map WebServer.run() stops with IOException");
|
||||
if(listeningThread != null) /* Only report this if we didn't initiate the shutdown */
|
||||
Log.info("map WebServer.run() stops with IOException");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -63,13 +65,14 @@ public class HttpServer extends Thread {
|
||||
|
||||
public void shutdown() {
|
||||
Log.info("Shutting down webserver...");
|
||||
listeningThread = null;
|
||||
try {
|
||||
if (sock != null) {
|
||||
sock.close();
|
||||
sock = null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.warning("Exception while closing socket for webserver shutdown", e);
|
||||
}
|
||||
listeningThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,6 @@ public class HttpServerConnection extends Thread {
|
||||
HttpRequest request = new HttpRequest();
|
||||
request.rmtaddr = rmtaddr;
|
||||
if (!readRequestHeader(in, request)) {
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -174,7 +173,6 @@ public class HttpServerConnection extends Thread {
|
||||
}
|
||||
|
||||
if (handler == null) {
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -186,10 +184,7 @@ public class HttpServerConnection extends Thread {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
Log.severe("HttpHandler '" + handler + "' has thown an exception", e);
|
||||
if (socket != null) {
|
||||
out.flush();
|
||||
socket.close();
|
||||
}
|
||||
out.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -211,37 +206,28 @@ public class HttpServerConnection extends Thread {
|
||||
if (responseBody == null) {
|
||||
Debug.debug("Response was given without Content-Length by '" + handler + "' for path '" + request.path + "'.");
|
||||
out.flush();
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out.flush();
|
||||
|
||||
if (!isKeepalive) {
|
||||
out.flush();
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
|
||||
out.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
} catch (Exception e) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
Log.severe("Exception while handling request: ", e);
|
||||
e.printStackTrace();
|
||||
return;
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,20 +111,13 @@ public abstract class FileHandler implements HttpHandler {
|
||||
while ((readBytes = fileInput.read(readBuffer)) > 0) {
|
||||
out.write(readBuffer, 0, readBytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
freeReadBuffer(readBuffer);
|
||||
if(fileInput != null) {
|
||||
closeFileInput(path, fileInput);
|
||||
fileInput = null;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
if (fileInput != null) {
|
||||
try { closeFileInput(path, fileInput); fileInput = null; } catch (IOException ex) { }
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.dynmap.Log;
|
||||
import org.dynmap.utils.FileLockManager;
|
||||
@@ -15,22 +16,37 @@ import org.dynmap.web.HttpResponse;
|
||||
|
||||
public class FilesystemHandler extends FileHandler {
|
||||
private File root;
|
||||
public FilesystemHandler(File root) {
|
||||
private boolean allow_symlinks = false;
|
||||
private String root_path;
|
||||
public FilesystemHandler(File root, boolean allow_symlinks) {
|
||||
if (!root.isDirectory())
|
||||
throw new IllegalArgumentException();
|
||||
this.root = root;
|
||||
this.allow_symlinks = allow_symlinks;
|
||||
this.root_path = root.getAbsolutePath();
|
||||
}
|
||||
@Override
|
||||
protected InputStream getFileInput(String path, HttpRequest request, HttpResponse response) {
|
||||
if(path == null) return null;
|
||||
path = getNormalizedPath(path); /* Resolve out relative stuff - nothing allowed above webroot */
|
||||
File file = new File(root, path);
|
||||
FileLockManager.getReadLock(file);
|
||||
if(!file.isFile())
|
||||
return null;
|
||||
if(!FileLockManager.getReadLock(file, 5000)) { /* Wait up to 5 seconds for lock */
|
||||
Log.severe("Timeout waiting for lock on file " + file.getPath());
|
||||
return null;
|
||||
}
|
||||
FileInputStream result = null;
|
||||
try {
|
||||
if (file.getCanonicalPath().startsWith(root.getAbsolutePath()) && file.isFile()) {
|
||||
FileInputStream result;
|
||||
String fpath;
|
||||
if(allow_symlinks)
|
||||
fpath = file.getAbsolutePath();
|
||||
else
|
||||
fpath = file.getCanonicalPath();
|
||||
if (fpath.startsWith(root_path)) {
|
||||
try {
|
||||
result = new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
FileLockManager.releaseReadLock(file);
|
||||
return null;
|
||||
}
|
||||
response.fields.put(HttpField.ContentLength, Long.toString(file.length()));
|
||||
@@ -38,14 +54,42 @@ public class FilesystemHandler extends FileHandler {
|
||||
}
|
||||
} catch(IOException ex) {
|
||||
Log.severe("Unable to get canoical path of requested file.", ex);
|
||||
} finally {
|
||||
if(result == null) FileLockManager.releaseReadLock(file);
|
||||
}
|
||||
FileLockManager.releaseReadLock(file);
|
||||
return null;
|
||||
}
|
||||
protected void closeFileInput(String path, InputStream in) throws IOException {
|
||||
super.closeFileInput(path, in);
|
||||
File file = new File(root, path);
|
||||
FileLockManager.releaseReadLock(file);
|
||||
path = getNormalizedPath(path);
|
||||
try {
|
||||
super.closeFileInput(path, in);
|
||||
} finally {
|
||||
File file = new File(root, path);
|
||||
FileLockManager.releaseReadLock(file);
|
||||
}
|
||||
}
|
||||
public static String getNormalizedPath(String p) {
|
||||
p = p.replace('\\', '/');
|
||||
String[] tok = p.split("/");
|
||||
int i, j;
|
||||
for(i = 0, j = 0; i < tok.length; i++) {
|
||||
if((tok[i] == null) || (tok[i].length() == 0) || (tok[i].equals("."))) {
|
||||
tok[i] = null;
|
||||
}
|
||||
else if(tok[i].equals("..")) {
|
||||
if(j > 0) { j--; tok[j] = null; }
|
||||
tok[i] = null;
|
||||
}
|
||||
else {
|
||||
tok[j] = tok[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
String path = "";
|
||||
for(i = 0; i < j; i++) {
|
||||
if(tok[i] != null)
|
||||
path = path + "/" + tok[i];
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: dynmap
|
||||
main: org.dynmap.DynmapPlugin
|
||||
version: 0.19
|
||||
version: "0.19.1"
|
||||
authors: [FrozenCow, mikeprimm, zeeZ]
|
||||
softdepend: [Permissions]
|
||||
commands:
|
||||
|
||||
+19
-11
@@ -131,18 +131,15 @@ DynMap.prototype = {
|
||||
if(urlarg != "") {
|
||||
me.defaultworld.defaultmap = me.defaultworld.maps[urlarg] || me.defaultworld.defaultmap;
|
||||
}
|
||||
urlarg = parseInt(me.getParameterByName('x'),10);
|
||||
if(urlarg != NaN) {
|
||||
urlarg = me.getIntParameterByName('x');
|
||||
if(urlarg != null)
|
||||
me.defaultworld.center.x = urlarg;
|
||||
}
|
||||
urlarg = parseInt(me.getParameterByName('y'),10);
|
||||
if(urlarg != NaN) {
|
||||
urlarg = me.getIntParameterByName('y');
|
||||
if(urlarg != null)
|
||||
me.defaultworld.center.y = urlarg;
|
||||
}
|
||||
urlarg = parseInt(me.getParameterByName('z'), 10);
|
||||
if(urlarg != NaN) {
|
||||
urlarg = me.getIntParameterByName('z');
|
||||
if(urlarg != null)
|
||||
me.defaultworld.center.z = urlarg;
|
||||
}
|
||||
},
|
||||
initialize: function() {
|
||||
var me = this;
|
||||
@@ -155,8 +152,9 @@ DynMap.prototype = {
|
||||
.addClass('map')
|
||||
.appendTo(container);
|
||||
|
||||
var urlzoom = parseInt(me.getParameterByName('zoom'),10);
|
||||
if(urlzoom != NaN) { me.options.defaultzoom = urlzoom; }
|
||||
var urlzoom = me.getIntParameterByName('zoom');
|
||||
if(urlzoom != null)
|
||||
me.options.defaultzoom = urlzoom;
|
||||
|
||||
var map = this.map = new google.maps.Map(mapContainer.get(0), {
|
||||
zoom: me.options.defaultzoom || 0,
|
||||
@@ -625,6 +623,16 @@ DynMap.prototype = {
|
||||
return "";
|
||||
else
|
||||
return decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
},
|
||||
getIntParameterByName: function(name) {
|
||||
var v = this.getParameterByName(name);
|
||||
if(v != "") {
|
||||
v = parseInt(v, 10);
|
||||
if(v != NaN) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// TODO: Enable hash-links.
|
||||
/* updateLink: function() {
|
||||
|
||||
@@ -1,9 +1,55 @@
|
||||
regionConstructors['polygon'] = function(map, name, region)
|
||||
{
|
||||
if(region.points) {
|
||||
var i;
|
||||
if(regionCfg.use3dregions) {
|
||||
var toppts = [];
|
||||
var botpts = [];
|
||||
for(i = 0; i < region.points.length; i++) {
|
||||
toppts.push(map.getProjection().fromWorldToLatLng(region.points[i].x,
|
||||
region['max-y'], region.points[i].z));
|
||||
botpts.push(map.getProjection().fromWorldToLatLng(region.points[i].x,
|
||||
region['min-y'], region.points[i].z));
|
||||
}
|
||||
for(i = 0; i < region.points.length; i++) {
|
||||
regionPolygons[name+'_side'+i] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
|
||||
paths: [
|
||||
toppts[i], botpts[i], botpts[(i+1)%region.points.length], toppts[(i+1)%region.points.length]
|
||||
], map: map }));
|
||||
google.maps.event.addListener(regionPolygons[name+'_side'+i] , 'click', function(event) {
|
||||
regionInfo(event, name, region);
|
||||
});
|
||||
}
|
||||
regionPolygons[name+'_bottom'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
|
||||
paths: botpts, map: map }));
|
||||
google.maps.event.addListener(regionPolygons[name+'_bottom'] , 'click', function(event) {
|
||||
regionInfo(event, name, region);
|
||||
});
|
||||
regionPolygons[name+'_top'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
|
||||
paths: toppts, map: map }));
|
||||
google.maps.event.addListener(regionPolygons[name+'_top'] , 'click', function(event) {
|
||||
regionInfo(event, name, region);
|
||||
});
|
||||
}
|
||||
else {
|
||||
var pts = [];
|
||||
var yy = (region['min-y']+region['max-y'])/2;
|
||||
for(i = 0; i < region.points.length; i++) {
|
||||
pts.push(map.getProjection().fromWorldToLatLng(region.points[i].x,
|
||||
yy, region.points[i].z));
|
||||
}
|
||||
regionPolygons[name+'_bottom'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
|
||||
paths: pts, map: map }));
|
||||
google.maps.event.addListener(regionPolygons[name+'_bottom'] , 'click', function(event) {
|
||||
regionInfo(event, name, region);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!region.min || !region.max)
|
||||
return;
|
||||
if(region.max.y > 64)
|
||||
region.max.y = 64;
|
||||
if(region.max.y <= region.min.y)
|
||||
region.min.y = region.max.y - 1;
|
||||
if(regionCfg.use3dregions)
|
||||
{
|
||||
regionPolygons[name+'_bottom'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
|
||||
|
||||
Reference in New Issue
Block a user