diff --git a/pom.xml b/pom.xml
index 308ecdc5..eafe0dc7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,8 +4,10 @@
dynmap
dynmap
+ ${maven.build.timestamp}
+ yyyy-MM-dd HH:mm
UTF-8
- Dev
+ Dev(${timestamp})
http://github.com/webbukkit/dynmap/
diff --git a/src/main/java/org/dynmap/bukkit/DynmapPlugin.java b/src/main/java/org/dynmap/bukkit/DynmapPlugin.java
index 94d8c03b..6b6a47fe 100644
--- a/src/main/java/org/dynmap/bukkit/DynmapPlugin.java
+++ b/src/main/java/org/dynmap/bukkit/DynmapPlugin.java
@@ -49,7 +49,6 @@ import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerBedLeaveEvent;
-import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
@@ -111,7 +110,17 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private Method ismodloaded;
private HashMap world_by_name = new HashMap();
private HashSet modsused = new HashSet();
+ // TPS calculator
+ private double tps;
+ private long lasttick;
+ private long perTickLimit;
+ private long cur_tick_starttime;
+ private long avgticklen = 50000000;
+ private int chunks_in_cur_tick = 0;
+ private long cur_tick;
+ private long prev_tick;
+
private HashMap sortWeights = new HashMap();
/* Lookup cache */
private World last_world;
@@ -201,8 +210,6 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
public class BukkitServer implements DynmapServerInterface {
/* Chunk load handling */
private Object loadlock = new Object();
- private int chunks_in_cur_tick = 0;
- private long cur_tick;
@Override
public int getBlockIDAt(String wname, int x, int y, int z) {
@@ -298,36 +305,22 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}, DynmapPlugin.this);
break;
case PLAYER_CHAT:
- try {
- Class.forName("org.bukkit.event.player.AsyncPlayerChatEvent");
- pm.registerEvents(new Listener() {
- @EventHandler(priority=EventPriority.MONITOR)
- public void onPlayerChat(AsyncPlayerChatEvent evt) {
- if(evt.isCancelled()) return;
- final Player p = evt.getPlayer();
- final String msg = evt.getMessage();
- getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
- public void run() {
- DynmapPlayer dp = null;
- if(p != null)
- dp = new BukkitPlayer(p);
- core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
- }
- });
- }
- }, DynmapPlugin.this);
- } catch (ClassNotFoundException cnfx) {
- pm.registerEvents(new Listener() {
- @EventHandler(priority=EventPriority.MONITOR)
- public void onPlayerChat(PlayerChatEvent evt) {
- if(evt.isCancelled()) return;
- DynmapPlayer p = null;
- if(evt.getPlayer() != null)
- p = new BukkitPlayer(evt.getPlayer());
- core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, p, evt.getMessage());
- }
- }, DynmapPlugin.this);
- }
+ pm.registerEvents(new Listener() {
+ @EventHandler(priority=EventPriority.MONITOR)
+ public void onPlayerChat(AsyncPlayerChatEvent evt) {
+ if(evt.isCancelled()) return;
+ final Player p = evt.getPlayer();
+ final String msg = evt.getMessage();
+ getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
+ public void run() {
+ DynmapPlayer dp = null;
+ if(p != null)
+ dp = new BukkitPlayer(p);
+ core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
+ }
+ });
+ }
+ }, DynmapPlugin.this);
break;
case BLOCK_BREAK:
pm.registerEvents(new Listener() {
@@ -458,22 +451,25 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
final MapChunkCache cc = c;
while(!cc.isDoneLoading()) {
- synchronized(loadlock) {
- long now = System.currentTimeMillis();
-
- if(cur_tick != (now/50)) { /* New tick? */
- chunks_in_cur_tick = mapManager.getMaxChunkLoadsPerTick();
- cur_tick = now/50;
- }
- }
Future f = core.getServer().callSyncMethod(new Callable() {
public Boolean call() throws Exception {
- boolean exhausted;
+ boolean exhausted = true;
+
synchronized(loadlock) {
+ if (prev_tick != cur_tick) {
+ prev_tick = cur_tick;
+ cur_tick_starttime = System.nanoTime();
+ }
if(chunks_in_cur_tick > 0) {
- chunks_in_cur_tick -= cc.loadChunks(chunks_in_cur_tick);
+ boolean done = false;
+ while (!done) {
+ int cnt = chunks_in_cur_tick;
+ if (cnt > 5) cnt = 5;
+ chunks_in_cur_tick -= cc.loadChunks(cnt);
+ exhausted = (chunks_in_cur_tick == 0) || ((System.nanoTime() - cur_tick_starttime) > perTickLimit);
+ done = exhausted || cc.isDoneLoading();
+ }
}
- exhausted = (chunks_in_cur_tick == 0);
}
return exhausted;
}
@@ -528,6 +524,11 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
return false;
}
+
+ @Override
+ public double getServerTPS() {
+ return tps;
+ }
}
/**
* Player access abstraction class
@@ -811,6 +812,16 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
else {
doEnable();
}
+ // Start tps calculation
+ lasttick = System.nanoTime();
+ tps = 20.0;
+ perTickLimit = core.getMaxTickUseMS() * 1000000;
+
+ getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
+ public void run() {
+ processTick();
+ }
+ }, 1, 1);
}
private boolean readyToEnable() {
@@ -872,7 +883,24 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
}
Log.info("Disabled");
}
-
+
+ private void processTick() {
+ long now = System.nanoTime();
+ long elapsed = now - lasttick;
+ lasttick = now;
+ avgticklen = ((avgticklen * 99) / 100) + (elapsed / 100);
+ tps = (double)1E9 / (double)avgticklen;
+ if (mapManager != null) {
+ chunks_in_cur_tick = mapManager.getMaxChunkLoadsPerTick();
+ }
+ cur_tick++;
+
+ // Tick core
+ if (core != null) {
+ core.serverTick(tps);
+ }
+ }
+
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
DynmapCommandSender dsender;
diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt
index 1094b6ba..853f2a61 100644
--- a/src/main/resources/configuration.txt
+++ b/src/main/resources/configuration.txt
@@ -310,9 +310,14 @@ updaterate: 2000
# If nonzero, server will pause fullrender/radiusrender processing when 'fullrenderplayerlimit' or more users are logged in
fullrenderplayerlimit: 0
-
# If nonzero, server will pause update render processing when 'updateplayerlimit' or more users are logged in
updateplayerlimit: 0
+# Target limit on server thread use - msec per tick
+per-tick-time-limit: 50
+# If TPS of server is below this setting, update renders processing is paused
+update-min-tps: 18.0
+# If TPS of server is below this setting, full/radius renders processing is paused
+fullrender-min-tps: 18.0
showplayerfacesinmenu: true