@Override public void run() { try { long start = System.nanoTime(); long stop; long delay; long timeStart = 0; long[] timeEnds = new long[12]; while (keepRunning) { stop = System.nanoTime(); logger.debug("Turn time elapsed: " + ((stop - start) / 1000) + " microsecs"); delay = turnDuration - ((stop - start) / 1000000); if (delay < 0) { StringBuilder sb = new StringBuilder(); for (long timeEnd : timeEnds) { sb.append(" " + (timeEnd - timeStart)); } logger.warn("Turn duration overflow by " + (-delay) + " ms: " + sb.toString()); } else if (delay > turnDuration) { logger.error( "Delay bigger than Turn duration. [delay: " + delay + "] [turnDuration:" + turnDuration + "]"); delay = 0; } // only sleep when the turn delay is > 0 if (delay > 0) { try { Thread.sleep(delay); } catch (InterruptedException e) { // ignore } } start = System.nanoTime(); timeStart = System.currentTimeMillis(); playerContainer.getLock().requestWriteLock(); try { timeEnds[0] = System.currentTimeMillis(); /* Get actions that players send */ scheduler.nextTurn(); timeEnds[1] = System.currentTimeMillis(); /* Execute them all */ scheduler.visit(ruleProcessor); timeEnds[2] = System.currentTimeMillis(); /* Compute game RP rules to move to the next turn */ ruleProcessor.endTurn(); timeEnds[3] = System.currentTimeMillis(); /* Send content that is waiting to players */ deliverTransferContent(); timeEnds[4] = System.currentTimeMillis(); /* Tell player what happened */ buildPerceptions(); timeEnds[5] = System.currentTimeMillis(); /* save players regularly to the db */ savePlayersPeriodicly(); timeEnds[6] = System.currentTimeMillis(); /* Move zone to the next turn */ world.nextTurn(); timeEnds[7] = System.currentTimeMillis(); turn++; ruleProcessor.beginTurn(); timeEnds[8] = System.currentTimeMillis(); } finally { playerContainer.getLock().releaseLock(); timeEnds[9] = System.currentTimeMillis(); } try { stats.set("Objects now", world.size()); } catch (ConcurrentModificationException e) { // TODO: size is obviously not threadsafe as it asks the underlying zone.objects for its // sizes, which are not threadsafe. } timeEnds[10] = System.currentTimeMillis(); TransactionPool.get().kickHangingTransactionsOfThisThread(); timeEnds[11] = System.currentTimeMillis(); } } catch (Throwable e) { logger.error("Unhandled exception, server will shut down.", e); } finally { isfinished = true; } }