/** * Constructor * * @param netMan the NetworkServerManager so that we can send message * @throws Exception in case of an unexpected error */ public RPServerManager(INetworkServerManager netMan) throws Exception { super("RPServerManager"); try { stats = Statistics.getStatistics(); keepRunning = true; isfinished = false; scheduler = new RPScheduler(); contentsToTransfer = new HashMap<RPObject, List<TransferContent>>(); playerContainer = PlayerEntryContainer.getContainer(); playersToRemove = new LinkedList<PlayerEntry>(); this.netMan = netMan; Configuration conf = Configuration.getConfiguration(); /* * This method loads the extensions that implement the game server * code. */ initializeExtensions(conf); String duration = conf.get("turn_length"); turnDuration = Long.parseLong(duration); turn = 0; } catch (Exception e) { logger.warn("ABORT: Unable to create RPZone, RPRuleProcessor or RPAIManager instances", e); throw e; } }
private void sendPlayerPerception( PlayerEntry entry, Perception perception, RPObject playerObject) { if (perception == null) { /** Until player enters game perception is null */ return; } MessageS2CPerception messages2cPerception = new MessageS2CPerception(entry.channel, perception); stats.add("Perceptions " + (perception.type == 0 ? "DELTA" : "SYNC"), 1); /* * The perception is build of two parts: the general information and the * private information about our object. This private information * consists only of attributes that are not visible to every player but * the owner, because visible attributes are already stored in the * perception. */ if (perception.type == Perception.SYNC) { RPObject copy = new RPObject(); copy.fill(playerObject); if (!playerObject.isHidden()) { copy.clearVisible(true); } messages2cPerception.setMyRPObject(copy, null); } else { RPObject added = new RPObject(); RPObject deleted = new RPObject(); try { playerObject.getDifferences(added, deleted); if (!playerObject.isHidden()) { added.clearVisible(false); deleted.clearVisible(false); } if (added.size() == 0) { added = null; } if (deleted.size() == 0) { deleted = null; } } catch (Exception e) { logger.error("Error getting object differences", e); logger.error(playerObject); added = null; deleted = null; } messages2cPerception.setMyRPObject(added, deleted); } messages2cPerception.setClientID(entry.clientid); messages2cPerception.setPerceptionTimestamp(entry.getPerceptionTimestamp()); messages2cPerception.setProtocolVersion(entry.getProtocolVersion()); netMan.sendMessage(messages2cPerception); }
@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; } }