Package marauroa.server

Source Code of marauroa.server.marauroad

/* $Id: marauroad.java,v 1.98 2010/12/26 21:12:35 nhnb Exp $ */
/***************************************************************************
*            (C) Copyright 2003 - Marauroa             *
***************************************************************************
***************************************************************************
*                                       *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                   *
*                                       *
***************************************************************************/
package marauroa.server;

// marauroa stuff
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.math.BigInteger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import marauroa.common.Configuration;
import marauroa.common.Log4J;
import marauroa.common.Logger;
import marauroa.common.MarauroaUncaughtExceptionHandler;
import marauroa.common.crypto.Hash;
import marauroa.common.crypto.RSAKey;
import marauroa.server.db.DatabaseConnectionException;
import marauroa.server.db.command.DBCommandQueue;
import marauroa.server.game.GameServerManager;
import marauroa.server.game.Statistics;
import marauroa.server.game.db.DatabaseFactory;
import marauroa.server.game.rp.RPServerManager;
import marauroa.server.net.INetworkServerManager;

/**
* The launcher of the whole Marauroa Server.<br>
* Marauroa is an arianne server application with an TCP transport.<br>
* Marauroa works by loading core class from your game server.
* <p>
* Marauroa server is and it is built using threads. marauroad has the following
* set of threads:
* <ul>
* <li> 1 thread to receive data from clients
* <li> 1 thread to send data to clients
* <li> 1 thread to handle the data into server actions
* <li> 1 thread to handle RPG itself.
* </ul>
*
* To denote the active behavior of the thread classes their names include the
* word Manager.<br>
* So marauroad has:
* <ul>
* <li> NetworkManager
* <li> GameManager
* <li> RPManager
* </ul>
*
* NetworkManager is the active thread that handles messages that come from the
* clients and converts them from a stream of bytes to a real Message object.
* See the Message Types document to understand what each message is for.<br>
* The pseudo code behind NetworkManager is:
*
* <pre>
*   forever
*   {
*   Read stream from network
*   Convert to a Message
*   store in our queue
*   }
* </pre>
*
* One level (conceptually) over NetworkManager is the GameManager, this is the
* part of the server that handles everything so that we can make the server
* work. Its main task is to process messages from clients and modify the state
* on the server to reflect the reply to that action, mainly related to:
* <ul>
* <li> Login
* <li> Logout
* <li> ChooseCharacter
* <li> Actions
* <li> Transfer Content
* </ul>
*
* See GameManager for a deeper understanding about what it does exactly.<br>
* The hardest part of the Manager is to consider all the special cases and all
* the exceptions that can happen. The main pseudo code of the GameManager, if
* we skip exceptions, is:
*
* <pre>
*   forever
*   {
*   Wait for Message to be available
*
*   if(Message is Login)
*   {
*   check player.
*   ask for character
*   }
*
*   if(Message is Choose Character)
*   {
*   check character
*   add to game
*   }
*
*   if(Message is Action)
*   {
*   add action to game
*   }
*
*   if(Message is Transfer Request ACK)
*   {
*   send client the content requested
*   }
*
*   if(Message is Logout)
*   {
*   remove from game
*   }
*   }
* </pre>
*
* And finally RPManager is the active thread that keeps executing actions.<br>
* Marauroa is, as you know, turn based, so actions when received are queued for
* the next turn, and when that turn is reached all the actions pending on that
* turn are executed.
* <p>
*
* The idea in RPManager is to split up complexity as much as possible: we have
* 2 entities to help it: Scheduler and RuleManager.
*
* <pre>
*   forever
*   {
*   for each action scheduled for this turn
*   {
*   run action in RuleManager
*   }
*
*   Send Perceptions
*
*   wait until turn is completed
*   next turn
*   }
* </pre>
*
* Scheduler handles the actions as they are sent by the GameManager.<br>
* RuleManager is a class that encapsulates all the implementation related to
* rules.
*
*/
public class marauroad extends Thread {

  /** the logger instance. */
  private static final Logger logger = Log4J.getLogger(marauroad.class);

  /** Which marauroa version are we running */
  private static final String VERSION = "3.8.7";

  /** Marauroa is a singleton. */
  private static marauroad marauroa;

  /** A network manager object to handle network events */
  private INetworkServerManager netMan;

  /** A game manager object to handle server glue logic and database stuff */
  private GameServerManager gameMan;

  /** Finally a rp game object that is coded on game's server plugin. */
  private RPServerManager rpMan;

  private static void setArguments(String[] args) {
    int i = 0;

    while (i != args.length) {
      if (args[i].equals("-c")) {
        Configuration.setConfigurationFile(args[i + 1]);
      } else if (args[i].equals("-h")) {
        System.out.println("Marauroa - an open source multiplayer online framework for game development -");
        System.out.println("Running on version " + VERSION);
        System.out.println("(C) 1999-2010 Miguel Angel Blanch Lardin and the Arianne project");
        System.out.println();
        System.out.println("usage: [-c server.ini]");
        System.out.println("\t-c: to choose a configuration file different of marauroa.ini or to use a");
        System.out.println("\t    different location to the file.");
        System.out.println("\t-h: print this help message");
        System.exit(0);
      }
      ++i;
    }
  }

  /**
   * Entry point
   *
   * @param args command line arguments
   */
  public static void main(String[] args) {
    System.out.println("Marauroa - arianne's open source multiplayer online framework for game development -");
    System.out.println("Running on version " + VERSION);
    System.out.println("(C) 1999-2011 Miguel Angel Blanch Lardin and the Arianne project");
    System.out.println();
    System.out.println("This program is free software; you can redistribute it and/or modify");
    System.out.println("it under the terms of the GNU General Public License as published by");
    System.out.println("the Free Software Foundation; either version 2 of the License, or");
    System.out.println("(at your option) any later version.");
    System.out.println();
    System.out.println("This program is distributed in the hope that it will be useful,");
    System.out.println("but WITHOUT ANY WARRANTY; without even the implied warranty of");
    System.out.println("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the");
    System.out.println("GNU General Public License for more details.");
    System.out.println();
    System.out.println("You should have received a copy of the GNU General Public License");
    System.out.println("along with this program; if not, write to the Free Software");
    System.out.println("Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA");
    System.out.println();

    marauroad.setArguments(args);

    String log4jConfiguration = null;

    try {
      Configuration conf = Configuration.getConfiguration();
      log4jConfiguration = conf.get("log4j_url");
    } catch (IOException e) {
      System.out.println("ERROR: Marauroa can't find configuration file.");
      System.out.println("Run game configuration to get a valid \"server.ini\" file");
      System.exit(1);
    }

    if(log4jConfiguration==null) {
      log4jConfiguration="marauroa/server/log4j.properties";
    }

    // Initialize Loggging
    try {
      Log4J.init(log4jConfiguration);
    } catch(Exception e) {
      System.out.println("ERROR: Marauroa can't initialize logging.");
      System.out.println("Verify you have created log/ directory.");
      System.exit(1);
    }

    // Check access to database is possible.
    try {
      new DatabaseFactory().initializeDatabase();
    } catch (DatabaseConnectionException e) {
      System.out.println("ERROR: Marauroa can't connect to database");
      System.out.println("Verify \"server.ini\" file to make sure access to database is possible.");
      System.exit(1);
    }

    marauroad.getMarauroa().start();
  }

  private void createBeanForStatistics() {
    // Adding a Bean for statistical access using jmanager
    try {
      MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
      // Unique identification of MBeans
      Statistics statBean = Statistics.getStatistics();
      // Uniquely identify the MBeans and register them with the platform
      // MBeanServer
      ObjectName statName = new ObjectName("marauroad:name=Statistics");
      mbs.registerMBean(statBean, statName);
      logger.debug("Statistics bean registered.");
    } catch (Exception e) {
      logger.error("cannot register statistics bean, continuing anyway.", e);
    }
  }

  @Override
  public synchronized void run() {
    long startTime = System.currentTimeMillis();
    logger.debug("marauroad thread started");

    createBeanForStatistics();

    boolean finish = false;

    if (!init()) {
      // initialize failed
      System.exit(-1);
    }

    double startupTime = (System.currentTimeMillis() - startTime) / 1000.0;

    logger.info("marauroa is up and running... (startup time: " + (long)(startupTime*10)/10. + " s)");
    while (!finish) {
      try {
        Statistics.getStatistics().print();
        wait(Statistics.DATABASE_STATISTICS_LAPSUS);
      } catch (InterruptedException e) {
        finish = true;
      }
    }

    finish();
    logger.debug("exiting marauroad thread");
  }

  /**
   * Constructor
   */
  protected marauroad() {
    super("marauroad");
  }

  /**
   * returns the marauroad object
   *
   * @return marauroad
   */
  public static marauroad getMarauroa() {
    if (marauroa == null) {
      marauroa = new marauroad();
    }

    return marauroa;
  }

  /**
   * Initializes the game. Returns true when all is OK, else false (this may
   * terminate the server).
   *
   * @return true, in case the startup was successful, false otherwise
   */
  public boolean init() {
    logger.debug("staring initialize");
    MarauroaUncaughtExceptionHandler.setup(true);

    // Initialize Secure random in an extra thread because it can take up
    // to 20 seconds on some computers with low entropy. The hard disk
    // access during start up will speed it up.
    new Thread() {
      @Override
      public void run() {
        Hash.random(4);
      }
    }.start();


    try {
      netMan = new marauroa.server.net.nio.NIONetworkServerManager();
      netMan.start();
    } catch (Exception e) {
      logger.error("Marauroa can't create NetworkServerManager.\n" + "Reasons:\n"
          + "- You are already running a copy of Marauroa on the same TCP port\n"
          + "- You haven't specified a valid configuration file\n"
          + "- You haven't create database\n"
          + "- You have invalid username and password to connect to database\n", e);
      return false;
    }

    try {
      rpMan = new RPServerManager(netMan);
      rpMan.start();
    } catch (Exception e) {
      logger.error(
              "Marauroa can't create RPServerManager.\n"
                  + "Reasons:\n"
                  + "- You haven't specified a valid configuration file\n"
                  + "- You haven't correctly filled the values related to game configuration. Use generateini application to create a valid configuration file.\n"
                  + "- There may be an error in the Game startup method.\n", e);
      return false;
    }

    try {
      if (Configuration.getConfiguration().get("n") == null) {
        throw new Exception("Missing RSA key pair in server.ini; run marauroa.tools.GenerateKeys");
      }
      RSAKey key = new RSAKey(new BigInteger(Configuration.getConfiguration().get("n")),
          new BigInteger(Configuration.getConfiguration().get("d")), new BigInteger(
              Configuration.getConfiguration().get("e")));

      gameMan = new GameServerManager(key, netMan, rpMan);
      gameMan.start();
    } catch (Exception e) {
      logger.error(
              "Marauroa can't create GameServerManager.\n"
                  + "Reasons:\n"
                  + "- You haven't specified a valid configuration file\n"
                  + "- You haven't correctly filled the values related to server information configuration. Use generateini application to create a valid configuration file.\n",
              e);
      return false;
    }

    Runtime.getRuntime().addShutdownHook(new Thread() {
      private final Logger log = Log4J.getLogger(marauroad.class);

      @Override
      public void run() {
        log.warn("User requesting shutdown");
        finish();
        log.info("Shutdown completed. See you later!");
      }
    });

    logger.debug("initialize finished");
    return true;
  }

  /**
   * shuts down Marauroa
   */
  public void finish() {
    netMan.finish();
    gameMan.finish();
    DBCommandQueue.get().finish();
  }
}
TOP

Related Classes of marauroa.server.marauroad

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.