mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-12-28 03:27:36 +01:00
Add support for saving/restoring of pending tile updates on server stops/start
This commit is contained in:
parent
0627e2675f
commit
0704413829
@ -1,7 +1,9 @@
|
|||||||
package org.dynmap;
|
package org.dynmap;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -45,6 +47,16 @@ public class AsynchronousQueue<T> {
|
|||||||
return set.size();
|
return set.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<T> popAll() {
|
||||||
|
List<T> s;
|
||||||
|
synchronized(lock) {
|
||||||
|
s = new ArrayList<T>(queue);
|
||||||
|
queue.clear();
|
||||||
|
set.clear();
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
thread = new Thread(new Runnable() {
|
thread = new Thread(new Runnable() {
|
||||||
|
@ -45,6 +45,7 @@ public class MapManager {
|
|||||||
private int max_chunk_loads_per_tick = DEFAULT_CHUNKS_PER_TICK;
|
private int max_chunk_loads_per_tick = DEFAULT_CHUNKS_PER_TICK;
|
||||||
private int parallelrendercnt = 0;
|
private int parallelrendercnt = 0;
|
||||||
private int progressinterval = 100;
|
private int progressinterval = 100;
|
||||||
|
private boolean saverestorepending = true;
|
||||||
|
|
||||||
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 */
|
||||||
/* Which fullrenders are active */
|
/* Which fullrenders are active */
|
||||||
@ -501,6 +502,7 @@ public class MapManager {
|
|||||||
parallelrendercnt = configuration.getInteger("parallelrendercnt", 0);
|
parallelrendercnt = configuration.getInteger("parallelrendercnt", 0);
|
||||||
progressinterval = configuration.getInteger("progressloginterval", 100);
|
progressinterval = configuration.getInteger("progressloginterval", 100);
|
||||||
if(progressinterval < 100) progressinterval = 100;
|
if(progressinterval < 100) progressinterval = 100;
|
||||||
|
saverestorepending = configuration.getBoolean("saverestorepending", true);
|
||||||
|
|
||||||
this.tileQueue = new AsynchronousQueue<MapTile>(
|
this.tileQueue = new AsynchronousQueue<MapTile>(
|
||||||
new Handler<MapTile>() {
|
new Handler<MapTile>() {
|
||||||
@ -708,6 +710,54 @@ public class MapManager {
|
|||||||
}
|
}
|
||||||
worldsLookup.put(w.getName(), dynmapWorld);
|
worldsLookup.put(w.getName(), dynmapWorld);
|
||||||
plug_in.events.trigger("worldactivated", dynmapWorld);
|
plug_in.events.trigger("worldactivated", dynmapWorld);
|
||||||
|
/* Now, restore any pending renders for this world */
|
||||||
|
if(saverestorepending)
|
||||||
|
loadPending(dynmapWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadPending(DynmapWorld w) {
|
||||||
|
File f = new File(plug_in.getDataFolder(), w.world.getName() + ".pending");
|
||||||
|
if(f.exists()) {
|
||||||
|
org.bukkit.util.config.Configuration saved = new org.bukkit.util.config.Configuration(f);
|
||||||
|
saved.load();
|
||||||
|
ConfigurationNode cn = new ConfigurationNode(saved);
|
||||||
|
/* Get the saved tile definitions */
|
||||||
|
List<ConfigurationNode> tiles = cn.getNodes("tiles");
|
||||||
|
if(tiles != null) {
|
||||||
|
int cnt = 0;
|
||||||
|
for(ConfigurationNode tile : tiles) {
|
||||||
|
MapTile mt = MapTile.restoreTile(w, tile); /* Restore tile, if possible */
|
||||||
|
if(mt != null) {
|
||||||
|
invalidateTile(mt);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cnt > 0)
|
||||||
|
Log.info("Loaded " + cnt + " pending tile renders for world '" + w.world.getName());
|
||||||
|
}
|
||||||
|
f.delete(); /* And clean it up */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void savePending() {
|
||||||
|
List<MapTile> mt = tileQueue.popAll();
|
||||||
|
for(DynmapWorld w : worlds) {
|
||||||
|
File f = new File(plug_in.getDataFolder(), w.world.getName() + ".pending");
|
||||||
|
org.bukkit.util.config.Configuration saved = new org.bukkit.util.config.Configuration(f);
|
||||||
|
ArrayList<ConfigurationNode> savedtiles = new ArrayList<ConfigurationNode>();
|
||||||
|
for(MapTile tile : mt) {
|
||||||
|
if(tile.getDynmapWorld() != w) continue;
|
||||||
|
ConfigurationNode tilenode = tile.saveTile();
|
||||||
|
if(tilenode != null) {
|
||||||
|
savedtiles.add(tilenode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(savedtiles.size() > 0) { /* Something to save? */
|
||||||
|
saved.setProperty("tiles", savedtiles);
|
||||||
|
saved.save();
|
||||||
|
Log.info("Saved " + savedtiles.size() + " pending tile renders in world '" + w.world.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int touch(Location l) {
|
public int touch(Location l) {
|
||||||
@ -773,6 +823,9 @@ public class MapManager {
|
|||||||
tileQueue.stop();
|
tileQueue.stop();
|
||||||
mapman = null;
|
mapman = null;
|
||||||
hdmapman = null;
|
hdmapman = null;
|
||||||
|
|
||||||
|
if(saverestorepending)
|
||||||
|
savePending();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<World, File> worldTileDirectories = new HashMap<World, File>();
|
private HashMap<World, File> worldTileDirectories = new HashMap<World, File>();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package org.dynmap;
|
package org.dynmap;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -54,4 +56,29 @@ public abstract class MapTile {
|
|||||||
public abstract int tileOrdinalX();
|
public abstract int tileOrdinalX();
|
||||||
public abstract int tileOrdinalY();
|
public abstract int tileOrdinalY();
|
||||||
|
|
||||||
|
public ConfigurationNode saveTile() {
|
||||||
|
ConfigurationNode cn = new ConfigurationNode();
|
||||||
|
cn.put("class", this.getClass().getName());
|
||||||
|
cn.put("data", saveTileData());
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String saveTileData();
|
||||||
|
|
||||||
|
public static MapTile restoreTile(DynmapWorld w, ConfigurationNode node) {
|
||||||
|
String cn = node.getString("class");
|
||||||
|
String dat = node.getString("data");
|
||||||
|
if((cn == null) || (dat == null)) return null;
|
||||||
|
try {
|
||||||
|
Class cls = Class.forName(cn);
|
||||||
|
Constructor con = cls.getConstructor(DynmapWorld.class, String.class);
|
||||||
|
return (MapTile)con.newInstance(w, dat);
|
||||||
|
} catch (ClassNotFoundException cnfx) {
|
||||||
|
} catch (NoSuchMethodException nsmx) {
|
||||||
|
} catch (InvocationTargetException itx) {
|
||||||
|
} catch (IllegalAccessException iax) {
|
||||||
|
} catch (InstantiationException ix) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,4 +80,5 @@ public abstract class MapType {
|
|||||||
* Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3)
|
* Values correspond to tile X,Y (0), X+step,Y (1), X,Y+step (2), X+step,Y+step (3)
|
||||||
*/
|
*/
|
||||||
public abstract int[] zoomFileStepSequence();
|
public abstract int[] zoomFileStepSequence();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -495,6 +495,28 @@ public class FlatMap extends MapType {
|
|||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FlatMapTile(DynmapWorld world, String parm) throws Exception {
|
||||||
|
super(world);
|
||||||
|
|
||||||
|
String[] parms = parm.split(",");
|
||||||
|
if(parms.length < 4) throw new Exception("wrong parameter count");
|
||||||
|
this.x = Integer.parseInt(parms[0]);
|
||||||
|
this.y = Integer.parseInt(parms[1]);
|
||||||
|
this.size = Integer.parseInt(parms[2]);
|
||||||
|
for(MapType t : world.maps) {
|
||||||
|
if(t.getName().equals(parms[3]) && (t instanceof FlatMap)) {
|
||||||
|
this.map = (FlatMap)t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this.map == null) throw new Exception("invalid map");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String saveTileData() {
|
||||||
|
return String.format("%d,%d,%d,%s", x, y, size, map.getName());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
if(fname == null) {
|
if(fname == null) {
|
||||||
|
@ -7,6 +7,8 @@ import org.dynmap.MapType;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.dynmap.MapTile;
|
import org.dynmap.MapTile;
|
||||||
|
import org.dynmap.kzedmap.KzedMap;
|
||||||
|
import org.dynmap.kzedmap.MapTileRenderer;
|
||||||
import org.dynmap.utils.MapChunkCache;
|
import org.dynmap.utils.MapChunkCache;
|
||||||
|
|
||||||
public class HDMapTile extends MapTile {
|
public class HDMapTile extends MapTile {
|
||||||
@ -20,6 +22,22 @@ public class HDMapTile extends MapTile {
|
|||||||
this.ty = ty;
|
this.ty = ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HDMapTile(DynmapWorld world, String parm) throws Exception {
|
||||||
|
super(world);
|
||||||
|
|
||||||
|
String[] parms = parm.split(",");
|
||||||
|
if(parms.length < 3) throw new Exception("wrong parameter count");
|
||||||
|
this.tx = Integer.parseInt(parms[0]);
|
||||||
|
this.ty = Integer.parseInt(parms[1]);
|
||||||
|
this.perspective = MapManager.mapman.hdmapman.perspectives.get(parms[2]);
|
||||||
|
if(this.perspective == null) throw new Exception("invalid perspective");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String saveTileData() {
|
||||||
|
return String.format("%d,%d,%s", tx, ty, perspective.getName());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
return getFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
|
return getFilename("hdmap", MapType.ImageFormat.FORMAT_PNG);
|
||||||
|
@ -3,11 +3,13 @@ package org.dynmap.kzedmap;
|
|||||||
import org.dynmap.DynmapChunk;
|
import org.dynmap.DynmapChunk;
|
||||||
import org.dynmap.DynmapWorld;
|
import org.dynmap.DynmapWorld;
|
||||||
import org.dynmap.MapManager;
|
import org.dynmap.MapManager;
|
||||||
|
import org.dynmap.MapType;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.dynmap.MapTile;
|
import org.dynmap.MapTile;
|
||||||
|
import org.dynmap.flat.FlatMap;
|
||||||
import org.dynmap.utils.MapChunkCache;
|
import org.dynmap.utils.MapChunkCache;
|
||||||
|
|
||||||
public class KzedMapTile extends MapTile {
|
public class KzedMapTile extends MapTile {
|
||||||
@ -28,6 +30,35 @@ public class KzedMapTile extends MapTile {
|
|||||||
this.py = py;
|
this.py = py;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KzedMapTile(DynmapWorld world, String parm) throws Exception {
|
||||||
|
super(world);
|
||||||
|
|
||||||
|
String[] parms = parm.split(",");
|
||||||
|
if(parms.length < 4) throw new Exception("wrong parameter count");
|
||||||
|
this.px = Integer.parseInt(parms[0]);
|
||||||
|
this.py = Integer.parseInt(parms[1]);
|
||||||
|
|
||||||
|
for(MapType t : world.maps) {
|
||||||
|
if(t.getName().equals(parms[2]) && (t instanceof KzedMap)) {
|
||||||
|
this.map = (KzedMap)t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this.map == null) throw new Exception("invalid map");
|
||||||
|
for(MapTileRenderer r : map.renderers) {
|
||||||
|
if(r.getName().equals(parms[3])) {
|
||||||
|
this.renderer = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this.renderer == null) throw new Exception("invalid renderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String saveTileData() {
|
||||||
|
return String.format("%d,%d,%s,%s", px, py, map.getName(), renderer.getName());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFilename() {
|
public String getFilename() {
|
||||||
if(fname == null) {
|
if(fname == null) {
|
||||||
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
import org.dynmap.DynmapChunk;
|
import org.dynmap.DynmapChunk;
|
||||||
import org.dynmap.DynmapWorld;
|
import org.dynmap.DynmapWorld;
|
||||||
import org.dynmap.MapTile;
|
import org.dynmap.MapTile;
|
||||||
|
import org.dynmap.MapType;
|
||||||
import org.dynmap.utils.MapChunkCache;
|
import org.dynmap.utils.MapChunkCache;
|
||||||
|
|
||||||
public class KzedZoomedMapTile extends MapTile {
|
public class KzedZoomedMapTile extends MapTile {
|
||||||
@ -42,6 +43,11 @@ public class KzedZoomedMapTile extends MapTile {
|
|||||||
this.originalTile = original;
|
this.originalTile = original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String saveTileData() {
|
||||||
|
return originalTile.saveTileData();
|
||||||
|
}
|
||||||
|
|
||||||
public int getTileX() {
|
public int getTileX() {
|
||||||
return ztilex(originalTile.px + KzedMap.tileWidth);
|
return ztilex(originalTile.px + KzedMap.tileWidth);
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,9 @@ renderacceleratethreshold: 60
|
|||||||
# How often to render tiles when backlog is above renderacceleratethreshold
|
# How often to render tiles when backlog is above renderacceleratethreshold
|
||||||
renderaccelerateinterval: 0.2
|
renderaccelerateinterval: 0.2
|
||||||
|
|
||||||
|
# Save and restore pending tile renders - prevents their loss on server shutdown or /reload
|
||||||
|
saverestorepending: true
|
||||||
|
|
||||||
# Zoom-out tile update period - how often to scan for and process tile updates into zoom-out tiles (in seconds)
|
# Zoom-out tile update period - how often to scan for and process tile updates into zoom-out tiles (in seconds)
|
||||||
zoomoutperiod: 30
|
zoomoutperiod: 30
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user