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