Add 'explosion' update trigger, add updated tile queue accelerator (to speed up processing if queue gets above a given threshold)

This commit is contained in:
Mike Primm 2011-08-21 05:28:37 +08:00 committed by mikeprimm
parent 43df59a88c
commit 9b191bb3ab
4 changed files with 88 additions and 30 deletions

View File

@ -12,10 +12,14 @@ public class AsynchronousQueue<T> {
private Set<T> set = new HashSet<T>(); private Set<T> set = new HashSet<T>();
private Handler<T> handler; private Handler<T> handler;
private int dequeueTime; private int dequeueTime;
private int accelDequeueTime;
public AsynchronousQueue(Handler<T> handler, int dequeueTime) { private int accelDequeueThresh;
public AsynchronousQueue(Handler<T> handler, int dequeueTime, int accelDequeueThresh, int accelDequeueTime) {
this.handler = handler; this.handler = handler;
this.dequeueTime = dequeueTime; this.dequeueTime = dequeueTime;
this.accelDequeueTime = accelDequeueTime;
this.accelDequeueThresh = accelDequeueThresh;
} }
public boolean push(T t) { public boolean push(T t) {
@ -83,7 +87,10 @@ public class AsynchronousQueue<T> {
if (t != null) { if (t != null) {
handler.handle(t); handler.handle(t);
} }
sleep(dequeueTime); if(set.size() >= accelDequeueThresh)
sleep(accelDequeueTime);
else
sleep(dequeueTime);
} }
} catch (Exception ex) { } catch (Exception ex) {

View File

@ -27,6 +27,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.CustomEventListener; import org.bukkit.event.CustomEventListener;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.Event.Type;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockBurnEvent;
@ -38,6 +39,8 @@ import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockSpreadEvent; import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.LeavesDecayEvent; import org.bukkit.event.block.LeavesDecayEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityListener;
import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerListener; import org.bukkit.event.player.PlayerListener;
@ -355,7 +358,7 @@ public class DynmapPlugin extends JavaPlugin {
private boolean onplayermove; private boolean onplayermove;
private boolean ongeneratechunk; private boolean ongeneratechunk;
private boolean onloadchunk; private boolean onloadchunk;
private boolean onexplosion;
public void registerEvents() { public void registerEvents() {
@ -517,26 +520,25 @@ public class DynmapPlugin extends JavaPlugin {
if(onplayermove) if(onplayermove)
registerEvent(Event.Type.PLAYER_MOVE, playerTrigger); registerEvent(Event.Type.PLAYER_MOVE, playerTrigger);
/* Register world event triggers */ /* Register entity event triggers */
ongeneratechunk = isTrigger("chunkgenerated"); EntityListener entityTrigger = new EntityListener() {
if(ongeneratechunk) { @Override
try { /* Test if new enough bukkit to allow this */ public void onEntityExplode(EntityExplodeEvent event) {
ChunkLoadEvent.class.getDeclaredMethod("isNewChunk", new Class[0]); List<Block> blocks = event.blockList();
} catch (NoSuchMethodException nsmx) { for(Block b: blocks) {
Log.info("Warning: CraftBukkit build does not support function needed for 'chunkgenerated' trigger - disabling"); Location loc = b.getLocation();
ongeneratechunk = false; mapManager.sscache.invalidateSnapshot(loc);
if(onexplosion) {
mapManager.touch(loc);
}
}
} }
} };
onloadchunk = isTrigger("chunkloaded"); onexplosion = isTrigger("explosion");
if(onloadchunk) { registerEvent(Event.Type.ENTITY_EXPLODE, entityTrigger);
generate_only = false;
}
else if (ongeneratechunk) { /* Register world event triggers */
generate_only = true;
}
registerEvent(Event.Type.CHUNK_LOAD, ourWorldEventHandler);
// To link configuration to real loaded worlds.
WorldListener worldTrigger = new WorldListener() { WorldListener worldTrigger = new WorldListener() {
@Override @Override
public void onChunkLoad(ChunkLoadEvent event) { public void onChunkLoad(ChunkLoadEvent event) {
@ -558,6 +560,26 @@ public class DynmapPlugin extends JavaPlugin {
mapManager.activateWorld(event.getWorld()); mapManager.activateWorld(event.getWorld());
} }
}; };
ongeneratechunk = isTrigger("chunkgenerated");
if(ongeneratechunk) {
try { /* Test if new enough bukkit to allow this */
ChunkLoadEvent.class.getDeclaredMethod("isNewChunk", new Class[0]);
} catch (NoSuchMethodException nsmx) {
Log.info("Warning: CraftBukkit build does not support function needed for 'chunkgenerated' trigger - disabling");
ongeneratechunk = false;
}
}
onloadchunk = isTrigger("chunkloaded");
if(onloadchunk) {
generate_only = false;
}
else if (ongeneratechunk) {
generate_only = true;
}
registerEvent(Event.Type.CHUNK_LOAD, worldTrigger);
// To link configuration to real loaded worlds.
registerEvent(Event.Type.WORLD_LOAD, worldTrigger); registerEvent(Event.Type.WORLD_LOAD, worldTrigger);
} }
@ -1046,6 +1068,21 @@ public class DynmapPlugin extends JavaPlugin {
} }
}; };
private EntityListener ourEntityEventHandler = new EntityListener() {
@Override
public void onEntityExplode(EntityExplodeEvent event) {
if(event.isCancelled())
return;
/* Call listeners */
List<Listener> ll = event_handlers.get(event.getType());
if(ll != null) {
for(Listener l : ll) {
((EntityListener)l).onEntityExplode(event);
}
}
}
};
/** /**
* Register event listener - this will be cleaned up properly on a /dynmap reload, unlike * Register event listener - this will be cleaned up properly on a /dynmap reload, unlike
* registering with Bukkit directly * registering with Bukkit directly
@ -1080,6 +1117,9 @@ public class DynmapPlugin extends JavaPlugin {
case CUSTOM_EVENT: case CUSTOM_EVENT:
pm.registerEvent(type, ourCustomEventHandler, Event.Priority.Monitor, this); pm.registerEvent(type, ourCustomEventHandler, Event.Priority.Monitor, this);
break; break;
case ENTITY_EXPLODE:
pm.registerEvent(type, ourEntityEventHandler, Event.Priority.Monitor, this);
break;
default: default:
Log.severe("registerEvent() in DynmapPlugin does not handle " + type); Log.severe("registerEvent() in DynmapPlugin does not handle " + type);
return; return;

View File

@ -488,12 +488,16 @@ public class MapManager {
sscache = new SnapshotCache(configuration.getInteger("snapshotcachesize", 500)); sscache = new SnapshotCache(configuration.getInteger("snapshotcachesize", 500));
parallelrendercnt = configuration.getInteger("parallelrendercnt", 0); parallelrendercnt = configuration.getInteger("parallelrendercnt", 0);
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() { this.tileQueue = new AsynchronousQueue<MapTile>(
@Override new Handler<MapTile>() {
public void handle(MapTile t) { @Override
scheduleDelayedJob(new FullWorldRenderState(t), 0); public void handle(MapTile t) {
} scheduleDelayedJob(new FullWorldRenderState(t), 0);
}, (int) (configuration.getDouble("renderinterval", 0.5) * 1000)); }
},
(int) (configuration.getDouble("renderinterval", 0.5) * 1000),
configuration.getInteger("renderacceleratethreshold", 30),
(int)(configuration.getDouble("renderaccelerateinterval", 0.2) * 1000));
/* On dedicated thread, so default to no delays */ /* On dedicated thread, so default to no delays */
timeslice_int = (long)(configuration.getDouble("timesliceinterval", 0.0) * 1000); timeslice_int = (long)(configuration.getDouble("timesliceinterval", 0.0) * 1000);

View File

@ -111,8 +111,14 @@ display-whitelist: false
# How often a tile gets rendered (in seconds). # How often a tile gets rendered (in seconds).
renderinterval: 1 renderinterval: 1
# How many tiles on update queue before accelerate render interval
renderacceleratethreshold: 60
# How often to render tiles when backlog is above renderacceleratethreshold
renderaccelerateinterval: 0.2
# 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: 60 zoomoutperiod: 30
# Tile hashing is used to minimize tile file updates when no changes have occurred - set to false to disable # Tile hashing is used to minimize tile file updates when no changes have occurred - set to false to disable
enabletilehash: true enabletilehash: true
@ -130,6 +136,7 @@ render-triggers:
- blockfaded - blockfaded
- blockspread - blockspread
- pistonmoved - pistonmoved
- explosion
# The path where the tile-files are placed. # The path where the tile-files are placed.
tilespath: web/tiles tilespath: web/tiles