예제 #1
0
  private void buildPerceptions() {
    playersToRemove.clear();

    /** We reset the cache at Perceptions */
    MessageS2CPerception.clearPrecomputedPerception();

    for (PlayerEntry entry : playerContainer) {
      try {
        // Before creating the perception we check the player is still there.
        if (entry.isTimeout()) {
          logger.info("Request (TIMEOUT) disconnection of Player " + entry.getAddress());
          playersToRemove.add(entry);
          continue;
        }

        if (entry.state == ClientState.GAME_BEGIN) {
          Perception perception = getPlayerPerception(entry);
          sendPlayerPerception(entry, perception, entry.object);
        }
      } catch (Exception e) {
        logger.error(
            "Removing player("
                + entry.clientid
                + ") because it caused a Exception while contacting it",
            e);
        playersToRemove.add(entry);
      }
    }

    for (PlayerEntry entry : playersToRemove) {
      logger.warn("RP Disconnecting entry: " + entry);
      netMan.disconnectClient(entry.channel);
    }
  }
예제 #2
0
  /**
   * 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;
    }
  }
예제 #3
0
 /**
  * Takes the given RPObject as the new RPObject representing the user's character. Does nothing if
  * the provided RPObject isn't the user's character object as determined by
  * isCharacter(newCharacter) or the provided RPObject is the same as the current one.
  *
  * @param newCharacter the new RPObject representing the users character
  */
 public void setCharacter(final RPObject newCharacter) {
   if (isCharacter(newCharacter) && this.myCharacter != newCharacter) {
     myCharacter = newCharacter;
     name = newCharacter.get("name");
   } else {
     log.warn("Character not set because it's not our character.");
   }
 }
예제 #4
0
  private void deliverTransferContent() {
    synchronized (contentsToTransfer) {
      for (Map.Entry<RPObject, List<TransferContent>> val : contentsToTransfer.entrySet()) {
        RPObject target = val.getKey();
        List<TransferContent> content = val.getValue();

        PlayerEntry entry = playerContainer.get(target);
        if (entry == null) {
          logger.warn(
              "Entry for player (" + target + ") does not exist: " + playerContainer,
              new Throwable());
          continue;
        }

        if (content == null) {
          logger.warn("content is null");
        }
        if (!entry.contentToTransfer.isEmpty()) {
          // prevent DoS if the client never confirms the Transfer offer
          if (entry.contentToTransfer.size() > 30) {
            synchronized (entry.contentToTransfer) {
              for (int i = 0; i < 10; i++) {
                entry.contentToTransfer.remove(0);
              }
            }
          }
          logger.warn(
              "Adding to existing contentToTransfer for player "
                  + entry.character
                  + " old: "
                  + entry.contentToTransfer
                  + " added "
                  + content);
        }
        entry.contentToTransfer.addAll(content);

        MessageS2CTransferREQ mes = new MessageS2CTransferREQ(entry.channel, content);
        mes.setClientID(entry.clientid);
        mes.setProtocolVersion(entry.getProtocolVersion());

        netMan.sendMessage(mes);
      }

      contentsToTransfer.clear();
    }
  }
예제 #5
0
  /**
   * This method disconnects a player from the server.
   *
   * @param object the player object that we want to disconnect from world
   */
  public void disconnectPlayer(RPObject object) {
    PlayerEntry entry = playerContainer.get(object);
    if (entry == null) {
      /*
       * There is no player entry for such channel This is not necesaryly
       * an error, as the connection could be anything else but an arianne
       * client or we are just disconnecting a player that logout
       * correctly.
       */
      logger.warn("There is no PlayerEntry associated to this RPObject.");
      return;
    }

    netMan.disconnectClient(entry.channel);
  }
예제 #6
0
  @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;
    }
  }