Merge pull request #2633 from Marvosg/v3.0

Resume full renders (skip already rendered tiles)
This commit is contained in:
mikeprimm 2019-12-15 01:10:28 -06:00 committed by GitHub
commit 49ea99b703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 278 additions and 44 deletions

View File

@ -1046,7 +1046,9 @@ public class DynmapCore implements DynmapCommonAPI {
new CommandInfo("dynmap", "render", "Renders the tile at your location."), new CommandInfo("dynmap", "render", "Renders the tile at your location."),
new CommandInfo("dynmap", "fullrender", "Render all maps for entire world from your location."), new CommandInfo("dynmap", "fullrender", "Render all maps for entire world from your location."),
new CommandInfo("dynmap", "fullrender", "<world>", "Render all maps for world <world>."), new CommandInfo("dynmap", "fullrender", "<world>", "Render all maps for world <world>."),
new CommandInfo("dynmap", "fullrender", "<world>:<map>", "Render map <map> of world'<world>."), new CommandInfo("dynmap", "fullrender", "<world>:<map>", "Render map <map> of world <world>."),
new CommandInfo("dynmap", "fullrender", "resume <world>", "Resume render of all maps for world <world>. Skip already rendered tiles."),
new CommandInfo("dynmap", "fullrender", "resume <world>:<map>", "Resume render of map <map> of world <world>. Skip already rendered tiles."),
new CommandInfo("dynmap", "radiusrender", "<radius>", "Render at least <radius> block radius from your location on all maps."), new CommandInfo("dynmap", "radiusrender", "<radius>", "Render at least <radius> block radius from your location on all maps."),
new CommandInfo("dynmap", "radiusrender", "<radius> <mapname>", "Render at least <radius> block radius from your location on map <mapname>."), new CommandInfo("dynmap", "radiusrender", "<radius> <mapname>", "Render at least <radius> block radius from your location on map <mapname>."),
new CommandInfo("dynmap", "radiusrender", "<world> <x> <z> <radius>", "Render at least <radius> block radius from location <x>,<z> on world <world>."), new CommandInfo("dynmap", "radiusrender", "<world> <x> <z> <radius>", "Render at least <radius> block radius from location <x>,<z> on world <world>."),
@ -1319,7 +1321,7 @@ public class DynmapCore implements DynmapCommonAPI {
loc = new DynmapLocation(w.getName(), x, 64, z); loc = new DynmapLocation(w.getName(), x, 64, z);
} }
if(loc != null) if(loc != null)
mapManager.renderFullWorld(loc, sender, mapname, true); mapManager.renderFullWorld(loc, sender, mapname, true, false);
} else if (c.equals("hide")) { } else if (c.equals("hide")) {
if (args.length == 1) { if (args.length == 1) {
if(player != null && checkPlayerPermission(sender,"hide.self")) { if(player != null && checkPlayerPermission(sender,"hide.self")) {
@ -1347,7 +1349,12 @@ public class DynmapCore implements DynmapCommonAPI {
} else if (c.equals("fullrender") && checkPlayerPermission(sender,"fullrender")) { } else if (c.equals("fullrender") && checkPlayerPermission(sender,"fullrender")) {
String map = null; String map = null;
if (args.length > 1) { if (args.length > 1) {
boolean resume = false;
for (int i = 1; i < args.length; i++) { for (int i = 1; i < args.length; i++) {
if (args[i].equalsIgnoreCase("resume")) {
resume = true;
continue;
}
int dot = args[i].indexOf(":"); int dot = args[i].indexOf(":");
DynmapWorld w; DynmapWorld w;
String wname = args[i]; String wname = args[i];
@ -1362,7 +1369,7 @@ public class DynmapCore implements DynmapCommonAPI {
loc = w.center; loc = w.center;
else else
loc = w.getSpawnLocation(); loc = w.getSpawnLocation();
mapManager.renderFullWorld(loc,sender, map, false); mapManager.renderFullWorld(loc,sender, map, false, resume);
} }
else else
sender.sendMessage("World '" + wname + "' not defined/loaded"); sender.sendMessage("World '" + wname + "' not defined/loaded");
@ -1372,7 +1379,7 @@ public class DynmapCore implements DynmapCommonAPI {
if(args.length > 1) if(args.length > 1)
map = args[1]; map = args[1];
if(loc != null) if(loc != null)
mapManager.renderFullWorld(loc, sender, map, false); mapManager.renderFullWorld(loc, sender, map, false, false);
} else { } else {
sender.sendMessage("World name is required"); sender.sendMessage("World name is required");
} }

View File

@ -22,6 +22,7 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@ -32,6 +33,10 @@ import org.dynmap.debug.Debug;
import org.dynmap.exporter.OBJExport; import org.dynmap.exporter.OBJExport;
import org.dynmap.hdmap.HDMapManager; import org.dynmap.hdmap.HDMapManager;
import org.dynmap.renderer.DynmapBlockState; import org.dynmap.renderer.DynmapBlockState;
import org.dynmap.storage.MapStorage;
import org.dynmap.storage.MapStorageBaseTileEnumCB;
import org.dynmap.storage.MapStorageTileSearchEndCB;
import org.dynmap.storage.MapStorageTile;
import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.MapChunkCache;
import org.dynmap.utils.Polygon; import org.dynmap.utils.Polygon;
import org.dynmap.utils.TileFlags; import org.dynmap.utils.TileFlags;
@ -67,7 +72,7 @@ public class MapManager {
private boolean tpspauseupdaterenders = false; private boolean tpspauseupdaterenders = false;
private boolean tpspausefullrenders = false; private boolean tpspausefullrenders = false;
private boolean tpspausezoomout = false; private boolean tpspausezoomout = false;
private boolean did_start = false; private boolean did_start = false;
private int zoomout_period = DEFAULT_ZOOMOUT_PERIOD; /* Zoom-out tile processing period, in seconds */ private int zoomout_period = DEFAULT_ZOOMOUT_PERIOD; /* Zoom-out tile processing period, in seconds */
@ -233,6 +238,7 @@ public class MapManager {
LinkedList<MapTile> renderQueue = null; LinkedList<MapTile> renderQueue = null;
MapTile tile0 = null; MapTile tile0 = null;
int rendercnt = 0; int rendercnt = 0;
int skipcnt = 0;
DynmapCommandSender sender; DynmapCommandSender sender;
String player; String player;
long timeaccum; long timeaccum;
@ -246,21 +252,51 @@ public class MapManager {
boolean shutdown = false; boolean shutdown = false;
boolean pausedforworld = false; boolean pausedforworld = false;
boolean updaterender = false; boolean updaterender = false;
boolean resume = false;
boolean quiet = false; boolean quiet = false;
String mapname; String mapname;
AtomicLong total_render_ns = new AtomicLong(0L); AtomicLong total_render_ns = new AtomicLong(0L);
AtomicInteger rendercalls = new AtomicInteger(0); AtomicInteger rendercalls = new AtomicInteger(0);
long lastPendingSaveTS = 0; // Timestamp of last pending state save (msec) long lastPendingSaveTS = 0; // Timestamp of last pending state save (msec)
HashSet<String> storedTileIds = new HashSet<>();
/* Full world, all maps render */ /* Full world, all maps render */
FullWorldRenderState(DynmapWorld dworld, DynmapLocation l, DynmapCommandSender sender, String mapname, boolean updaterender) { FullWorldRenderState(DynmapWorld dworld, DynmapLocation l, DynmapCommandSender sender, String mapname, boolean updaterender, boolean resume) {
this(dworld, l, sender, mapname, -1); this(dworld, l, sender, mapname, -1);
if(updaterender) { if(updaterender) {
rendertype = RENDERTYPE_UPDATERENDER; rendertype = RENDERTYPE_UPDATERENDER;
this.updaterender = true; this.updaterender = true;
} }
else else {
rendertype = RENDERTYPE_FULLRENDER; rendertype = RENDERTYPE_FULLRENDER;
}
this.resume = resume;
final CountDownLatch latch = new CountDownLatch(1);
if (resume) { // if resume render
final MapStorage ms = world.getMapStorage();
ms.enumMapBaseTiles(world, map, new MapStorageBaseTileEnumCB() {
@Override
public void tileFound(MapStorageTile tile, MapType.ImageEncoding enc) {
String tileId = String.format("%s_%s_%d_%d", tile.world.getName(), tile.map.getName(), tile.x, tile.y);
//sender.sendMessage("Tile found: " + tileId);
storedTileIds.add(tileId);
}
}, new MapStorageTileSearchEndCB() {
@Override
public void searchEnded() {
latch.countDown();
}
});
try {
latch.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
sender.sendMessage(e.toString());
}
}
} }
/* Full world, all maps render, with optional render radius */ /* Full world, all maps render, with optional render radius */
@ -481,13 +517,22 @@ public class MapManager {
if(rndcalls == 0) rndcalls = 1; if(rndcalls == 0) rndcalls = 1;
double rendtime = total_render_ns.doubleValue() * 0.000001 / rndcalls; double rendtime = total_render_ns.doubleValue() * 0.000001 / rndcalls;
if(activemapcnt > 1) { if(activemapcnt > 1) {
sendMessage(String.format("%s of maps [%s] of '%s' completed - %d tiles rendered each (%.2f msec/map-tile, %.2f msec per render)", if (skipcnt > 1)
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime)); sendMessage(String.format("%s of maps [%s] of '%s' completed - %d tiles rendered each (%.2f msec/map-tile, %.2f msec per render) (%d tiles skipped)",
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime, skipcnt));
else
sendMessage(String.format("%s of maps [%s] of '%s' completed - %d tiles rendered each (%.2f msec/map-tile, %.2f msec per render)",
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime));
} }
else { else {
sendMessage(String.format("%s of map '%s' of '%s' completed - %d tiles rendered (%.2f msec/map-tile, %.2f msec per render)", if (skipcnt > 1)
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime)); sendMessage(String.format("%s of map '%s' of '%s' completed - %d tiles rendered (%.2f msec/map-tile, %.2f msec per render) (%d tiles skipped)",
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime, skipcnt));
else
sendMessage(String.format("%s of map '%s' of '%s' completed - %d tiles rendered (%.2f msec/map-tile, %.2f msec per render)",
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime));
} }
skipcnt = 0;
/* Now, if fullrender, use the render bitmap to purge obsolete tiles */ /* Now, if fullrender, use the render bitmap to purge obsolete tiles */
if(rendertype.equals(RENDERTYPE_FULLRENDER)) { if(rendertype.equals(RENDERTYPE_FULLRENDER)) {
if(activemapcnt == 1) { if(activemapcnt == 1) {
@ -698,19 +743,37 @@ public class MapManager {
chunks_read[cs.ordinal()].addAndGet(cache.getChunksLoaded(cs)); chunks_read[cs.ordinal()].addAndGet(cache.getChunksLoaded(cs));
chunks_read_times[cs.ordinal()].addAndGet(cache.getTotalRuntimeNanos(cs)); chunks_read_times[cs.ordinal()].addAndGet(cache.getTotalRuntimeNanos(cs));
} }
boolean skipTile = false;
if (resume) {
String tileId = String.format("%s_%s_%d_%d", tile.world.getName(), map.getName(), tile.tileOrdinalX(), tile.tileOrdinalY());
skipTile = storedTileIds.contains(tileId);
}
if(tile0 != null) { /* Single tile? */ if(tile0 != null) { /* Single tile? */
if(cache.isEmpty() == false) if(cache.isEmpty() == false) {
tile.render(cache, null); if (skipTile) {
skipcnt++;
} else {
tile.render(cache, null);
}
}
} }
else { else {
/* Remove tile from tile queue, since we're processing it already */ /* Remove tile from tile queue, since we're processing it already */
tileQueue.remove(tile); tileQueue.remove(tile);
/* Switch to not checking if rendered tile is blank - breaks us on skylands, where tiles can be nominally blank - just work off chunk cache empty */ /* Switch to not checking if rendered tile is blank - breaks us on skylands, where tiles can be nominally blank - just work off chunk cache empty */
if (cache.isEmpty() == false) { if (cache.isEmpty() == false) {
long rt0 = System.nanoTime(); boolean upd;
boolean upd = tile.render(cache, mapname); if (skipTile) {
total_render_ns.addAndGet(System.nanoTime()-rt0); upd = false;
rendercalls.incrementAndGet(); skipcnt++;
} else {
long rt0 = System.nanoTime();
upd = tile.render(cache, mapname);
total_render_ns.addAndGet(System.nanoTime()-rt0);
rendercalls.incrementAndGet();
}
synchronized(lock) { synchronized(lock) {
rendered.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), true); rendered.setFlag(tile.tileOrdinalX(), tile.tileOrdinalY(), true);
if(upd || (!updaterender)) { /* If updated or not an update render */ if(upd || (!updaterender)) { /* If updated or not an update render */
@ -733,12 +796,22 @@ public class MapManager {
if (rndcalls == 0) rndcalls = 1; if (rndcalls == 0) rndcalls = 1;
double rendtime = total_render_ns.doubleValue() * 0.000001 / rndcalls; double rendtime = total_render_ns.doubleValue() * 0.000001 / rndcalls;
double msecpertile = (double)timeaccum / (double)rendercnt / (double)activemapcnt; double msecpertile = (double)timeaccum / (double)rendercnt / (double)activemapcnt;
if(activemapcnt > 1) if(activemapcnt > 1) {
sendMessage(String.format("%s of maps [%s] of '%s' in progress - %d tiles rendered each (%.2f msec/map-tile, %.2f msec per render)", if (skipcnt > 1)
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime)); sendMessage(String.format("%s of maps [%s] of '%s' in progress - %d tiles rendered each (%.2f msec/map-tile, %.2f msec per render) (%d tiles skipped)",
else rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime, skipcnt));
sendMessage(String.format("%s of map '%s' of '%s' in progress - %d tiles rendered (%.2f msec/tile, %.2f msec per render)", else
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime)); sendMessage(String.format("%s of maps [%s] of '%s' in progress - %d tiles rendered each (%.2f msec/map-tile, %.2f msec per render)",
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime));
} else {
if (skipcnt > 1)
sendMessage(String.format("%s of map '%s' of '%s' in progress - %d tiles rendered (%.2f msec/tile, %.2f msec per render) (%d tiles skipped)",
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime, skipcnt));
else
sendMessage(String.format("%s of map '%s' of '%s' in progress - %d tiles rendered (%.2f msec/tile, %.2f msec per render)",
rendertype, activemaps, world.getName(), rendercnt, msecpertile, rendtime));
}
skipcnt = 0;
} }
} }
} }
@ -751,6 +824,7 @@ public class MapManager {
public void cancelRender() { public void cancelRender() {
cancelled = true; cancelled = true;
storedTileIds.clear();
} }
public void shutdownRender() { public void shutdownRender() {
@ -968,7 +1042,7 @@ public class MapManager {
tileQueue.start(); tileQueue.start();
} }
void renderFullWorld(DynmapLocation l, DynmapCommandSender sender, String mapname, boolean update) { void renderFullWorld(DynmapLocation l, DynmapCommandSender sender, String mapname, boolean update, boolean resume) {
DynmapWorld world = getWorld(l.world); DynmapWorld world = getWorld(l.world);
if (world == null) { if (world == null) {
sender.sendMessage("Could not render: world '" + l.world + "' not defined in configuration."); sender.sendMessage("Could not render: world '" + l.world + "' not defined in configuration.");
@ -982,7 +1056,7 @@ public class MapManager {
sender.sendMessage(rndr.rendertype + " of world '" + wname + "' already active."); sender.sendMessage(rndr.rendertype + " of world '" + wname + "' already active.");
return; return;
} }
rndr = new FullWorldRenderState(world,l,sender, mapname, update); /* Make new activation record */ rndr = new FullWorldRenderState(world,l,sender, mapname, update, resume); /* Make new activation record */
active_renders.put(wname, rndr); /* Add to active table */ active_renders.put(wname, rndr); /* Add to active table */
} }
/* Schedule first tile to be worked */ /* Schedule first tile to be worked */
@ -990,6 +1064,8 @@ public class MapManager {
if(update) if(update)
sender.sendMessage("Update render starting on world '" + wname + "'..."); sender.sendMessage("Update render starting on world '" + wname + "'...");
else if (resume)
sender.sendMessage("Full render resuming on world '" + wname + "'...");
else else
sender.sendMessage("Full render starting on world '" + wname + "'..."); sender.sendMessage("Full render starting on world '" + wname + "'...");
} }

View File

@ -86,6 +86,15 @@ public abstract class MapStorage {
*/ */
public abstract void enumMapTiles(DynmapWorld world, MapType map, MapStorageTileEnumCB cb); public abstract void enumMapTiles(DynmapWorld world, MapType map, MapStorageTileEnumCB cb);
/**
* Enumerate existing map tiles, matching given constraints, with zoom at 0
* @param world - specific world
* @param map - specific map (if non-null)
* @param cbBase - callback to receive matching tiles
* @param cbEnd - callback to receive end-of-search event
*/
public abstract void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd);
/** /**
* Purge existing map tiles, matching given constraints * Purge existing map tiles, matching given constraints
* @param world - specific world * @param world - specific world

View File

@ -0,0 +1,12 @@
package org.dynmap.storage;
import org.dynmap.MapType.ImageEncoding;
public interface MapStorageBaseTileEnumCB {
/**
* Callback for base (non-zoomed) tile enumeration calls
* @param tile - tile found
* @param enc - image encoding
*/
public void tileFound(MapStorageTile tile, ImageEncoding enc);
}

View File

@ -0,0 +1,10 @@
package org.dynmap.storage;
import org.dynmap.MapType.ImageEncoding;
public interface MapStorageTileSearchEndCB {
/**
* Callback for end of tile enumeration calls
*/
public void searchEnded();
}

View File

@ -22,6 +22,8 @@ import org.dynmap.debug.Debug;
import org.dynmap.storage.MapStorage; import org.dynmap.storage.MapStorage;
import org.dynmap.storage.MapStorageTile; import org.dynmap.storage.MapStorageTile;
import org.dynmap.storage.MapStorageTileEnumCB; import org.dynmap.storage.MapStorageTileEnumCB;
import org.dynmap.storage.MapStorageBaseTileEnumCB;
import org.dynmap.storage.MapStorageTileSearchEndCB;
import org.dynmap.utils.BufferInputStream; import org.dynmap.utils.BufferInputStream;
import org.dynmap.utils.BufferOutputStream; import org.dynmap.utils.BufferOutputStream;
@ -295,9 +297,13 @@ public class FileTreeMapStorage extends MapStorage {
} }
private void processEnumMapTiles(DynmapWorld world, MapType map, File base, ImageVariant var, MapStorageTileEnumCB cb) { private void processEnumMapTiles(DynmapWorld world, MapType map, File base, ImageVariant var, MapStorageTileEnumCB cb, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
File bdir = new File(base, map.getPrefix() + var.variantSuffix); File bdir = new File(base, map.getPrefix() + var.variantSuffix);
if (bdir.isDirectory() == false) return; if (bdir.isDirectory() == false) {
if(cbEnd != null)
cbEnd.searchEnded();
return;
}
LinkedList<File> dirs = new LinkedList<File>(); // List to traverse LinkedList<File> dirs = new LinkedList<File>(); // List to traverse
dirs.add(bdir); // Directory for map dirs.add(bdir); // Directory for map
@ -343,7 +349,10 @@ public class FileTreeMapStorage extends MapStorage {
int y = Integer.parseInt(coord[1]); int y = Integer.parseInt(coord[1]);
// Invoke callback // Invoke callback
MapStorageTile t = new StorageTile(world, map, x, y, zoom, var); MapStorageTile t = new StorageTile(world, map, x, y, zoom, var);
cb.tileFound(t, fmt); if(cb != null)
cb.tileFound(t, fmt);
if(cbBase != null && t.zoom == 0)
cbBase.tileFound(t, fmt);
t.cleanup(); t.cleanup();
} catch (NumberFormatException nfx) { } catch (NumberFormatException nfx) {
} }
@ -351,6 +360,9 @@ public class FileTreeMapStorage extends MapStorage {
} }
} }
} }
if(cbEnd != null) {
cbEnd.searchEnded();
}
} }
@Override @Override
@ -367,7 +379,26 @@ public class FileTreeMapStorage extends MapStorage {
for (MapType mt : mtlist) { for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants(); ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) { for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, base, var, cb); processEnumMapTiles(world, mt, base, var, cb, null, null);
}
}
}
@Override
public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
File base = new File(baseTileDir, world.getName()); // Get base directory for world
List<MapType> mtlist;
if (map != null) {
mtlist = Collections.singletonList(map);
}
else { // Else, add all directories under world directory (for maps)
mtlist = new ArrayList<MapType>(world.maps);
}
for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, base, var, null, cbBase, cbEnd);
} }
} }
} }

View File

@ -25,6 +25,8 @@ import org.dynmap.PlayerFaces.FaceType;
import org.dynmap.storage.MapStorage; import org.dynmap.storage.MapStorage;
import org.dynmap.storage.MapStorageTile; import org.dynmap.storage.MapStorageTile;
import org.dynmap.storage.MapStorageTileEnumCB; import org.dynmap.storage.MapStorageTileEnumCB;
import org.dynmap.storage.MapStorageBaseTileEnumCB;
import org.dynmap.storage.MapStorageTileSearchEndCB;
import org.dynmap.utils.BufferInputStream; import org.dynmap.utils.BufferInputStream;
import org.dynmap.utils.BufferOutputStream; import org.dynmap.utils.BufferOutputStream;
@ -608,7 +610,7 @@ public class MariaDBMapStorage extends MapStorage {
@Override @Override
public void enumMapTiles(DynmapWorld world, MapType map, public void enumMapTiles(DynmapWorld world, MapType map,
MapStorageTileEnumCB cb) { MapStorageTileEnumCB cb) {
List<MapType> mtlist; List<MapType> mtlist;
if (map != null) { if (map != null) {
@ -620,15 +622,36 @@ public class MariaDBMapStorage extends MapStorage {
for (MapType mt : mtlist) { for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants(); ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) { for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, var, cb); processEnumMapTiles(world, mt, var, cb, null, null);
} }
} }
} }
private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb) { @Override
public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
List<MapType> mtlist;
if (map != null) {
mtlist = Collections.singletonList(map);
}
else { // Else, add all directories under world directory (for maps)
mtlist = new ArrayList<MapType>(world.maps);
}
for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, var, null, cbBase, cbEnd);
}
}
}
private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
Connection c = null; Connection c = null;
boolean err = false; boolean err = false;
Integer mapkey = getMapKey(world, map, var); Integer mapkey = getMapKey(world, map, var);
if (mapkey == null) return; if (mapkey == null) {
if(cbEnd != null)
cbEnd.searchEnded();
return;
}
try { try {
c = getConnection(); c = getConnection();
// Query tiles for given mapkey // Query tiles for given mapkey
@ -636,9 +659,15 @@ public class MariaDBMapStorage extends MapStorage {
ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM " + tableTiles + " WHERE MapID=" + mapkey + ";"); ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM " + tableTiles + " WHERE MapID=" + mapkey + ";");
while (rs.next()) { while (rs.next()) {
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var); StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
cb.tileFound(st, MapType.ImageEncoding.fromOrd(rs.getInt("Format"))); final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
if(cb != null)
cb.tileFound(st, encoding);
if(cbBase != null && st.zoom == 0)
cbBase.tileFound(st, encoding);
st.cleanup(); st.cleanup();
} }
if(cbEnd != null)
cbEnd.searchEnded();
rs.close(); rs.close();
stmt.close(); stmt.close();
} catch (SQLException x) { } catch (SQLException x) {

View File

@ -25,6 +25,8 @@ import org.dynmap.PlayerFaces.FaceType;
import org.dynmap.storage.MapStorage; import org.dynmap.storage.MapStorage;
import org.dynmap.storage.MapStorageTile; import org.dynmap.storage.MapStorageTile;
import org.dynmap.storage.MapStorageTileEnumCB; import org.dynmap.storage.MapStorageTileEnumCB;
import org.dynmap.storage.MapStorageBaseTileEnumCB;
import org.dynmap.storage.MapStorageTileSearchEndCB;
import org.dynmap.utils.BufferInputStream; import org.dynmap.utils.BufferInputStream;
import org.dynmap.utils.BufferOutputStream; import org.dynmap.utils.BufferOutputStream;
@ -610,7 +612,7 @@ public class MySQLMapStorage extends MapStorage {
@Override @Override
public void enumMapTiles(DynmapWorld world, MapType map, public void enumMapTiles(DynmapWorld world, MapType map,
MapStorageTileEnumCB cb) { MapStorageTileEnumCB cb) {
List<MapType> mtlist; List<MapType> mtlist;
if (map != null) { if (map != null) {
@ -622,15 +624,36 @@ public class MySQLMapStorage extends MapStorage {
for (MapType mt : mtlist) { for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants(); ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) { for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, var, cb); processEnumMapTiles(world, mt, var, cb, null, null);
} }
} }
} }
private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb) { @Override
public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
List<MapType> mtlist;
if (map != null) {
mtlist = Collections.singletonList(map);
}
else { // Else, add all directories under world directory (for maps)
mtlist = new ArrayList<MapType>(world.maps);
}
for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, var, null, cbBase, cbEnd);
}
}
}
private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
Connection c = null; Connection c = null;
boolean err = false; boolean err = false;
Integer mapkey = getMapKey(world, map, var); Integer mapkey = getMapKey(world, map, var);
if (mapkey == null) return; if (mapkey == null) {
if(cbEnd != null)
cbEnd.searchEnded();
return;
}
try { try {
c = getConnection(); c = getConnection();
// Query tiles for given mapkey // Query tiles for given mapkey
@ -638,9 +661,15 @@ public class MySQLMapStorage extends MapStorage {
ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM " + tableTiles + " WHERE MapID=" + mapkey + ";"); ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM " + tableTiles + " WHERE MapID=" + mapkey + ";");
while (rs.next()) { while (rs.next()) {
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var); StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
cb.tileFound(st, MapType.ImageEncoding.fromOrd(rs.getInt("Format"))); final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
if(cb != null)
cb.tileFound(st, encoding);
if(cbBase != null && st.zoom == 0)
cbBase.tileFound(st, encoding);
st.cleanup(); st.cleanup();
} }
if(cbEnd != null)
cbEnd.searchEnded();
rs.close(); rs.close();
stmt.close(); stmt.close();
} catch (SQLException x) { } catch (SQLException x) {

View File

@ -23,6 +23,8 @@ import org.dynmap.PlayerFaces.FaceType;
import org.dynmap.storage.MapStorage; import org.dynmap.storage.MapStorage;
import org.dynmap.storage.MapStorageTile; import org.dynmap.storage.MapStorageTile;
import org.dynmap.storage.MapStorageTileEnumCB; import org.dynmap.storage.MapStorageTileEnumCB;
import org.dynmap.storage.MapStorageBaseTileEnumCB;
import org.dynmap.storage.MapStorageTileSearchEndCB;
import org.dynmap.utils.BufferInputStream; import org.dynmap.utils.BufferInputStream;
import org.dynmap.utils.BufferOutputStream; import org.dynmap.utils.BufferOutputStream;
@ -541,7 +543,7 @@ public class SQLiteMapStorage extends MapStorage {
@Override @Override
public void enumMapTiles(DynmapWorld world, MapType map, public void enumMapTiles(DynmapWorld world, MapType map,
MapStorageTileEnumCB cb) { MapStorageTileEnumCB cb) {
List<MapType> mtlist; List<MapType> mtlist;
if (map != null) { if (map != null) {
@ -553,15 +555,38 @@ public class SQLiteMapStorage extends MapStorage {
for (MapType mt : mtlist) { for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants(); ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) { for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, var, cb); processEnumMapTiles(world, mt, var, cb, null, null);
} }
} }
} }
private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb) {
@Override
public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
List<MapType> mtlist;
if (map != null) {
mtlist = Collections.singletonList(map);
}
else { // Else, add all directories under world directory (for maps)
mtlist = new ArrayList<MapType>(world.maps);
}
for (MapType mt : mtlist) {
ImageVariant[] vars = mt.getVariants();
for (ImageVariant var : vars) {
processEnumMapTiles(world, mt, var, null, cbBase, cbEnd);
}
}
}
private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) {
Connection c = null; Connection c = null;
boolean err = false; boolean err = false;
Integer mapkey = getMapKey(world, map, var); Integer mapkey = getMapKey(world, map, var);
if (mapkey == null) return; if (mapkey == null) {
if(cbEnd != null)
cbEnd.searchEnded();
return;
}
try { try {
c = getConnection(); c = getConnection();
// Query tiles for given mapkey // Query tiles for given mapkey
@ -570,9 +595,15 @@ public class SQLiteMapStorage extends MapStorage {
ResultSet rs = doExecuteQuery(stmt, "SELECT x,y,zoom,Format FROM Tiles WHERE MapID=" + mapkey + ";"); ResultSet rs = doExecuteQuery(stmt, "SELECT x,y,zoom,Format FROM Tiles WHERE MapID=" + mapkey + ";");
while (rs.next()) { while (rs.next()) {
StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var); StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var);
cb.tileFound(st, MapType.ImageEncoding.fromOrd(rs.getInt("Format"))); final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format"));
if(cb != null)
cb.tileFound(st, encoding);
if(cbBase != null && st.zoom == 0)
cbBase.tileFound(st, encoding);
st.cleanup(); st.cleanup();
} }
if(cbEnd != null)
cbEnd.searchEnded();
rs.close(); rs.close();
stmt.close(); stmt.close();
} catch (SQLException x) { } catch (SQLException x) {