mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-11-24 19:25:15 +01:00
Add queued update triggers for zoom-out updates - deals with file time
resolution issues on Linux (1 second is too long to be reliable)
This commit is contained in:
parent
d63db655d8
commit
214fec208d
@ -33,7 +33,7 @@ public class ClientConfigurationComponent extends Component {
|
|||||||
s(wo, "center/y", wn.getFloat("center/y", 64.0f));
|
s(wo, "center/y", wn.getFloat("center/y", 64.0f));
|
||||||
s(wo, "center/z", wn.getFloat("center/z", 0.0f));
|
s(wo, "center/z", wn.getFloat("center/z", 0.0f));
|
||||||
s(wo, "bigworld", world.bigworld);
|
s(wo, "bigworld", world.bigworld);
|
||||||
s(wo, "extrazoomout", world.extrazoomoutlevels);
|
s(wo, "extrazoomout", world.getExtraZoomOutLevels());
|
||||||
a(t, "worlds", wo);
|
a(t, "worlds", wo);
|
||||||
|
|
||||||
for(MapType mt : world.maps) {
|
for(MapType mt : world.maps) {
|
||||||
|
@ -16,6 +16,7 @@ import java.io.File;
|
|||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
@ -31,8 +32,39 @@ public class DynmapWorld {
|
|||||||
public boolean sendposition;
|
public boolean sendposition;
|
||||||
public boolean sendhealth;
|
public boolean sendhealth;
|
||||||
public boolean bigworld; /* If true, deeper directory hierarchy */
|
public boolean bigworld; /* If true, deeper directory hierarchy */
|
||||||
public int extrazoomoutlevels; /* Number of additional zoom out levels to generate */
|
private int extrazoomoutlevels; /* Number of additional zoom out levels to generate */
|
||||||
public File worldtilepath;
|
public File worldtilepath;
|
||||||
|
private Object lock = new Object();
|
||||||
|
private HashSet<File> zoomoutupdates[];
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void setExtraZoomOutLevels(int lvl) {
|
||||||
|
extrazoomoutlevels = lvl;
|
||||||
|
zoomoutupdates = new HashSet[lvl];
|
||||||
|
for(int i = 0; i < lvl; i++)
|
||||||
|
zoomoutupdates[i] = new HashSet<File>();
|
||||||
|
}
|
||||||
|
public int getExtraZoomOutLevels() { return extrazoomoutlevels; }
|
||||||
|
|
||||||
|
public void enqueueZoomOutUpdate(File f) {
|
||||||
|
enqueueZoomOutUpdate(f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enqueueZoomOutUpdate(File f, int level) {
|
||||||
|
if(level >= extrazoomoutlevels)
|
||||||
|
return;
|
||||||
|
synchronized(lock) {
|
||||||
|
zoomoutupdates[level].add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean popQueuedUpdate(File f, int level) {
|
||||||
|
if(level >= extrazoomoutlevels)
|
||||||
|
return false;
|
||||||
|
synchronized(lock) {
|
||||||
|
return zoomoutupdates[level].remove(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class DirFilter implements FilenameFilter {
|
private static class DirFilter implements FilenameFilter {
|
||||||
public boolean accept(File f, String n) {
|
public boolean accept(File f, String n) {
|
||||||
@ -73,11 +105,40 @@ public class DynmapWorld {
|
|||||||
String zfnprefix;
|
String zfnprefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File based scan - used for priming map after server startup
|
||||||
|
* @param zoomlevel
|
||||||
|
*/
|
||||||
public void freshenZoomOutFilesByLevel(int zoomlevel) {
|
public void freshenZoomOutFilesByLevel(int zoomlevel) {
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ")");
|
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ")");
|
||||||
if(worldtilepath.exists() == false) /* Quit if not found */
|
if(worldtilepath.exists() == false) /* Quit if not found */
|
||||||
return;
|
return;
|
||||||
|
HashMap<String, PrefixData> maptab = buildPrefixData(zoomlevel);
|
||||||
|
|
||||||
|
if(bigworld) { /* If big world, next directories are map name specific */
|
||||||
|
DirFilter df = new DirFilter();
|
||||||
|
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
|
||||||
|
PrefixData pd = maptab.get(pfx);
|
||||||
|
File dname = new File(worldtilepath, pfx);
|
||||||
|
/* Now, go through subdirectories under this one, and process them */
|
||||||
|
String[] subdir = dname.list(df);
|
||||||
|
if(subdir == null) continue;
|
||||||
|
for(String s : subdir) {
|
||||||
|
File sdname = new File(dname, s);
|
||||||
|
cnt += processZoomDirectory(sdname, pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { /* Else, classic file layout */
|
||||||
|
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
|
||||||
|
cnt += processZoomDirectory(worldtilepath, maptab.get(pfx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ") - done (" + cnt + " updated files)");
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<String, PrefixData> buildPrefixData(int zoomlevel) {
|
||||||
HashMap<String, PrefixData> maptab = new HashMap<String, PrefixData>();
|
HashMap<String, PrefixData> maptab = new HashMap<String, PrefixData>();
|
||||||
/* Build table of file prefixes and step sizes */
|
/* Build table of file prefixes and step sizes */
|
||||||
for(MapType mt : maps) {
|
for(MapType mt : maps) {
|
||||||
@ -85,8 +146,8 @@ public class DynmapWorld {
|
|||||||
int stepsize = mt.baseZoomFileStepSize();
|
int stepsize = mt.baseZoomFileStepSize();
|
||||||
boolean neg_step_x = false;
|
boolean neg_step_x = false;
|
||||||
if(stepsize < 0) {
|
if(stepsize < 0) {
|
||||||
stepsize = -stepsize;
|
stepsize = -stepsize;
|
||||||
neg_step_x = true;
|
neg_step_x = true;
|
||||||
}
|
}
|
||||||
int[] stepseq = mt.zoomFileStepSequence();
|
int[] stepseq = mt.zoomFileStepSequence();
|
||||||
for(String p : pfx) {
|
for(String p : pfx) {
|
||||||
@ -115,26 +176,7 @@ public class DynmapWorld {
|
|||||||
maptab.put(p, pd);
|
maptab.put(p, pd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(bigworld) { /* If big world, next directories are map name specific */
|
return maptab;
|
||||||
DirFilter df = new DirFilter();
|
|
||||||
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
|
|
||||||
PrefixData pd = maptab.get(pfx);
|
|
||||||
File dname = new File(worldtilepath, pfx);
|
|
||||||
/* Now, go through subdirectories under this one, and process them */
|
|
||||||
String[] subdir = dname.list(df);
|
|
||||||
if(subdir == null) continue;
|
|
||||||
for(String s : subdir) {
|
|
||||||
File sdname = new File(dname, s);
|
|
||||||
cnt += processZoomDirectory(sdname, pd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { /* Else, classic file layout */
|
|
||||||
for(String pfx : maptab.keySet()) { /* Walk through prefixes, as directories */
|
|
||||||
cnt += processZoomDirectory(worldtilepath, maptab.get(pfx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Debug.debug("freshenZoomOutFiles(" + world.getName() + "," + zoomlevel + ") - done (" + cnt + " updated files)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ProcessTileRec {
|
private static class ProcessTileRec {
|
||||||
@ -158,51 +200,13 @@ public class DynmapWorld {
|
|||||||
if(files == null)
|
if(files == null)
|
||||||
return 0;
|
return 0;
|
||||||
for(String fn : files) {
|
for(String fn : files) {
|
||||||
/* Build file object */
|
ProcessTileRec tr = processZoomFile(new File(dir, fn), pd);
|
||||||
File f = new File(dir, fn);
|
if(tr != null) {
|
||||||
/* Parse filename to predict zoomed out file */
|
String zfpath = tr.zf.getPath();
|
||||||
fn = fn.substring(0, fn.lastIndexOf('.')); /* Strip off extension */
|
if(!toprocess.containsKey(zfpath)) {
|
||||||
String[] tok = fn.split("_"); /* Split by underscores */
|
toprocess.put(zfpath, tr);
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
boolean parsed = false;
|
|
||||||
if(tok.length >= 2) {
|
|
||||||
try {
|
|
||||||
x = Integer.parseInt(tok[tok.length-2]);
|
|
||||||
y = Integer.parseInt(tok[tok.length-1]);
|
|
||||||
parsed = true;
|
|
||||||
} catch (NumberFormatException nfx) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!parsed)
|
|
||||||
continue;
|
|
||||||
if(pd.neg_step_x) x = -x;
|
|
||||||
if(x >= 0)
|
|
||||||
x = x - (x % (2*step));
|
|
||||||
else
|
|
||||||
x = x + (x % (2*step));
|
|
||||||
if(pd.neg_step_x) x = -x;
|
|
||||||
if(y >= 0)
|
|
||||||
y = y - (y % (2*step));
|
|
||||||
else
|
|
||||||
y = y + (y % (2*step));
|
|
||||||
/* Make name of corresponding zoomed tile */
|
|
||||||
String zfname = makeFilePath(pd, x, y, true);
|
|
||||||
File zf = new File(worldtilepath, zfname);
|
|
||||||
long fts = f.lastModified();
|
|
||||||
/* If zoom file exists and is older than our file, nothing to do */
|
|
||||||
if(zf.exists() && ((zf.lastModified() >= f.lastModified()) || checkIgnoreUpdate(f, fts))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String zfpath = zf.getPath();
|
|
||||||
if(!toprocess.containsKey(zfpath)) {
|
|
||||||
ProcessTileRec rec = new ProcessTileRec();
|
|
||||||
rec.zf = zf;
|
|
||||||
rec.x = x;
|
|
||||||
rec.y = y;
|
|
||||||
rec.zfname = zfname;
|
|
||||||
toprocess.put(zfpath, rec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
/* Do processing */
|
/* Do processing */
|
||||||
@ -214,6 +218,50 @@ public class DynmapWorld {
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ProcessTileRec processZoomFile(File f, PrefixData pd) {
|
||||||
|
int step = pd.stepsize << pd.zoomlevel;
|
||||||
|
String fn = f.getName();
|
||||||
|
/* Parse filename to predict zoomed out file */
|
||||||
|
fn = fn.substring(0, fn.lastIndexOf('.')); /* Strip off extension */
|
||||||
|
String[] tok = fn.split("_"); /* Split by underscores */
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
boolean parsed = false;
|
||||||
|
if(tok.length >= 2) {
|
||||||
|
try {
|
||||||
|
x = Integer.parseInt(tok[tok.length-2]);
|
||||||
|
y = Integer.parseInt(tok[tok.length-1]);
|
||||||
|
parsed = true;
|
||||||
|
} catch (NumberFormatException nfx) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!parsed)
|
||||||
|
return null;
|
||||||
|
if(pd.neg_step_x) x = -x;
|
||||||
|
if(x >= 0)
|
||||||
|
x = x - (x % (2*step));
|
||||||
|
else
|
||||||
|
x = x + (x % (2*step));
|
||||||
|
if(pd.neg_step_x) x = -x;
|
||||||
|
if(y >= 0)
|
||||||
|
y = y - (y % (2*step));
|
||||||
|
else
|
||||||
|
y = y + (y % (2*step));
|
||||||
|
/* Make name of corresponding zoomed tile */
|
||||||
|
String zfname = makeFilePath(pd, x, y, true);
|
||||||
|
File zf = new File(worldtilepath, zfname);
|
||||||
|
/* If we're not updated, and zoom file exists and is older than our file, nothing to do */
|
||||||
|
if((!popQueuedUpdate(f, pd.zoomlevel)) && zf.exists() && (zf.lastModified() >= f.lastModified())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ProcessTileRec rec = new ProcessTileRec();
|
||||||
|
rec.zf = zf;
|
||||||
|
rec.x = x;
|
||||||
|
rec.y = y;
|
||||||
|
rec.zfname = zfname;
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
private void processZoomTile(PrefixData pd, File dir, File zf, String zfname, int tx, int ty) {
|
private void processZoomTile(PrefixData pd, File dir, File zf, String zfname, int tx, int ty) {
|
||||||
Debug.debug("processZoomFile(" + pd.baseprefix + "," + dir.getPath() + "," + zf.getPath() + "," + tx + "," + ty + ")");
|
Debug.debug("processZoomFile(" + pd.baseprefix + "," + dir.getPath() + "," + zf.getPath() + "," + tx + "," + ty + ")");
|
||||||
int width = 128, height = 128;
|
int width = 128, height = 128;
|
||||||
@ -285,31 +333,12 @@ public class DynmapWorld {
|
|||||||
}
|
}
|
||||||
hashman.updateHashCode(key, null, tilex, tiley, crc);
|
hashman.updateHashCode(key, null, tilex, tiley, crc);
|
||||||
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
|
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
|
||||||
|
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
zf.setLastModified(System.currentTimeMillis()); /* Touch the existing file */
|
zf.setLastModified(System.currentTimeMillis()); /* Touch the existing file */
|
||||||
// ignoreUpdate(zf); /* Remember to ignore this update */
|
|
||||||
}
|
}
|
||||||
FileLockManager.releaseWriteLock(zf);
|
FileLockManager.releaseWriteLock(zf);
|
||||||
KzedMap.freeBufferedImage(kzIm);
|
KzedMap.freeBufferedImage(kzIm);
|
||||||
}
|
}
|
||||||
private HashMap<String, Long> ignore_upd = new HashMap<String, Long>();
|
|
||||||
|
|
||||||
private void ignoreUpdate(File f) {
|
|
||||||
long ts = f.lastModified();
|
|
||||||
ignore_upd.put(f.getPath(), ts);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Check if ignore for file at current timestamp - return true if so
|
|
||||||
*/
|
|
||||||
private boolean checkIgnoreUpdate(File f, long ts) {
|
|
||||||
String fn = f.getPath();
|
|
||||||
Long its = ignore_upd.get(fn);
|
|
||||||
if((its != null) && (ts <= its.longValue())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ignore_upd.remove(fn); /* If newer, stop ignoring */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -361,7 +361,7 @@ public class MapManager {
|
|||||||
dynmapWorld.sendposition = worldConfiguration.getBoolean("sendposition", true);
|
dynmapWorld.sendposition = worldConfiguration.getBoolean("sendposition", true);
|
||||||
dynmapWorld.sendhealth = worldConfiguration.getBoolean("sendhealth", true);
|
dynmapWorld.sendhealth = worldConfiguration.getBoolean("sendhealth", true);
|
||||||
dynmapWorld.bigworld = worldConfiguration.getBoolean("bigworld", false);
|
dynmapWorld.bigworld = worldConfiguration.getBoolean("bigworld", false);
|
||||||
dynmapWorld.extrazoomoutlevels = worldConfiguration.getInteger("extrazoomout", 0);
|
dynmapWorld.setExtraZoomOutLevels(worldConfiguration.getInteger("extrazoomout", 0));
|
||||||
dynmapWorld.worldtilepath = new File(plug_in.tilesDirectory, w.getName());
|
dynmapWorld.worldtilepath = new File(plug_in.tilesDirectory, w.getName());
|
||||||
if(loclist != null) {
|
if(loclist != null) {
|
||||||
for(ConfigurationNode loc : loclist) {
|
for(ConfigurationNode loc : loclist) {
|
||||||
|
@ -289,6 +289,7 @@ public class FlatMap extends MapType {
|
|||||||
}
|
}
|
||||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
|
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
|
||||||
hashman.updateHashCode(tile.getKey(), null, t.x, t.y, crc);
|
hashman.updateHashCode(tile.getKey(), null, t.x, t.y, crc);
|
||||||
|
tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile);
|
||||||
tile_update = true;
|
tile_update = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -316,6 +317,7 @@ public class FlatMap extends MapType {
|
|||||||
}
|
}
|
||||||
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getDayFilename()));
|
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getDayFilename()));
|
||||||
hashman.updateHashCode(tile.getKey(), "day", t.x, t.y, crc);
|
hashman.updateHashCode(tile.getKey(), "day", t.x, t.y, crc);
|
||||||
|
tile.getDynmapWorld().enqueueZoomOutUpdate(dayfile);
|
||||||
tile_update = true;
|
tile_update = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -317,6 +317,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
|||||||
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
|
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
|
||||||
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
||||||
new Client.Tile(zmtile.getFilename()));
|
new Client.Tile(zmtile.getFilename()));
|
||||||
|
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile);
|
||||||
ztile_updated = true;
|
ztile_updated = true;
|
||||||
}
|
}
|
||||||
KzedMap.freeBufferedImage(zimg);
|
KzedMap.freeBufferedImage(zimg);
|
||||||
@ -331,6 +332,7 @@ public class DefaultTileRenderer implements MapTileRenderer {
|
|||||||
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
|
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
|
||||||
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
MapManager.mapman.pushUpdate(zmtile.getWorld(),
|
||||||
new Client.Tile(zmtile.getDayFilename()));
|
new Client.Tile(zmtile.getDayFilename()));
|
||||||
|
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile_day);
|
||||||
ztile_updated = true;
|
ztile_updated = true;
|
||||||
}
|
}
|
||||||
KzedMap.freeBufferedImage(zimg_day);
|
KzedMap.freeBufferedImage(zimg_day);
|
||||||
|
Loading…
Reference in New Issue
Block a user