Package org.pokenet.server.network

Source Code of org.pokenet.server.network.LoginManager

package org.pokenet.server.network;

import java.net.Socket;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Queue;

import org.apache.mina.core.session.IoSession;
import org.pokenet.server.GameServer;
import org.pokenet.server.backend.entity.Bag;
import org.pokenet.server.backend.entity.PlayerChar;
import org.pokenet.server.backend.entity.PokemonBox;
import org.pokenet.server.backend.entity.PlayerChar.Language;
import org.pokenet.server.battle.DataService;
import org.pokenet.server.battle.Pokemon;
import org.pokenet.server.battle.PokemonSpecies;
import org.pokenet.server.battle.Pokemon.ExpTypes;
import org.pokenet.server.battle.mechanics.PokemonNature;
import org.pokenet.server.battle.mechanics.moves.MoveListEntry;
import org.pokenet.server.feature.TimeService;

/**
* Handles logging players in
* @author shadowkanji
*
*/
public class LoginManager implements Runnable {
  private Queue<Object []> m_loginQueue;
  private Thread m_thread;
  private boolean m_isRunning;
  private MySqlManager m_database;
 
  private Queue<Object []> m_passChangeQueue;
 
  /**
   * Default constructor. Requires a logout manager to be passed in so the server
   * can check if player's data is not being saved as they are logging in.
   * @param manager
   */
  public LoginManager(LogoutManager manager) {
    m_database = new MySqlManager();
    m_loginQueue = new LinkedList<Object []>();
    m_passChangeQueue = new LinkedList<Object []>();
    m_thread = null;
  }
 
  /**
   * Returns the ip address of a session
   * @param s
   * @return
   */
  private String getIp(IoSession s) {
    if(s != null) {
      String ip = s.getRemoteAddress().toString();
      ip = ip.substring(1);
      ip = ip.substring(0, ip.indexOf(":"));
      return ip;
    } else {
      return "";
    }
  }
 
  /**
   * Attempts to login a player. Upon success, it sends a packet to the player to inform them they are logged in.
   * @param session
   * @param l
   * @param username
   * @param password
   */
  private void attemptLogin(IoSession session, char l, String username, String password) {
    try {
      //Check if we haven't reach the player limit
      if(TcpProtocolHandler.getPlayerCount() >= GameServer.getMaxPlayers()) {
        session.write("l2");
        return;
      }
      //First connect to the database
      m_database = new MySqlManager();
      if(!m_database.connect(GameServer.getDatabaseHost(), GameServer.getDatabaseUsername(), GameServer.getDatabasePassword())) {
        session.write("l1");
        return;
      }
      //Select the database
      if(!m_database.selectDatabase(GameServer.getDatabaseName())) {
        session.write("l1");
        return;
      }
      //Now, check they are not banned
      ResultSet result = m_database.query("SELECT * FROM pn_bans WHERE ip='" + getIp(session) + "'");
      if(result != null && result.first()) {
        //This is player is banned, inform them
        session.write("l4");
        return;
      }
      //Then find the member's information
      result = m_database.query("SELECT * FROM pn_members WHERE username='" + MySqlManager.parseSQL(username) + "'");
      if(!result.first()){
        //Member doesn't exist, say user or pass wrong. We don't want someone to guess usernames.
        session.write("le");
        return;
      }
      //Check if the password is correct
      if(result.getString("password").compareTo(password) == 0) {
        //Remove the player from the map to prevent duplicates
        GameServer.getServiceManager().getMovementService().removePlayer(username);
        long time = System.currentTimeMillis();
        //Now check if they are logged in anywhere else
        if(result.getString("lastLoginServer").equalsIgnoreCase(GameServer.getServerName())) {
          /*
           * They are already logged in on this server.
           * Attach the session to the existing player if they exist, if not, just log them in
           */
          if(TcpProtocolHandler.containsPlayer(username)) {
            PlayerChar p = TcpProtocolHandler.getPlayer(username);
            p.getTcpSession().setAttribute("player", null);
            p.setLastLoginTime(time);
            p.getTcpSession().close(true);
            p.setTcpSession(session);
            p.setLanguage(Language.values()[Integer.parseInt(String.valueOf(l))]);
            m_database.query("UPDATE pn_members SET lastLoginServer='" + MySqlManager.parseSQL(GameServer.getServerName()) + "', lastLoginTime='" + time + "' WHERE username='" + MySqlManager.parseSQL(username) + "'");
            m_database.query("UPDATE pn_members SET lastLoginIP='" + getIp(session) + "' WHERE username='" + MySqlManager.parseSQL(username) + "'");
            m_database.query("UPDATE pn_members SET lastLanguageUsed='" + l + "' WHERE username='" + MySqlManager.parseSQL(username) + "'");
            session.setAttribute("player", p);
            this.initialiseClient(p, session);
          } else {
            session.write("l3");
            return;
          }
        } else if(result.getString("lastLoginServer").equalsIgnoreCase("null")) {
          /*
           * They are not logged in elsewhere, log them in
           */
          this.login(username, l, session, result);
        } else {
          /*
           * They are logged in somewhere else.
           * Check if the server is up, if it is, don't log them in. If not, log them in
           */
//          if(InetAddress.getByName(result.getString("lastLoginServer")).isReachable(5000)) {
//            session.write("l3");
//            return;
//          } else {
//            //The server they were on went down and they are trying to login elsewhere
//            this.login(username, l, session, result);
//          }
          try{
            /**
             * This is a dirty hack. The old method used isReachable(5000) to determine if the server was alive.
             * isReachable doesn't work unless you run as root due to sending IMCP Echo packets being forbidden
             * under normal user accounts.
             *
             *  Instead, We open a socket to determine if server's alive. If it crashes, then server's down.
             */
            Socket socket = new Socket(result.getString("lastLoginServer"),7002);
            socket.close();
            session.write("l3");
            return;
          }catch(Exception e){
            //The server they were on went down and they are trying to login elsewhere
            this.login(username, l, session, result);
          }
        }
      } else {
        //Password is wrong, say so.
        session.write("le");
        return;
      }
      m_database.close();
    } catch (Exception e) {
      e.printStackTrace();
      session.write("lu");
      /*
       * Something went wrong so make sure the player is registered as logged out
       */
      m_database.query("UPDATE pn_members SET lastLoginServer='null' WHERE username='" + MySqlManager.parseSQL(username) + "'");
      m_database.close();
    }
  }
 
  /**
   * Places a player in the login queue
   * @param session
   * @param username
   * @param password
   * @param forceLogin - true if player wants to force login
   */
  public void queuePlayer(IoSession session, String username, String password) {
    if(m_thread == null || !m_thread.isAlive()) {
      start();
    }
    m_loginQueue.offer(new Object[] {session, username, password});
  }
 
  /**
   * Places a player in the queue to update their password
   * @param session
   * @param username
   * @param newPassword
   * @param oldPassword
   */
  public void queuePasswordChange(IoSession session, String username, String newPassword, String oldPassword) {
    if(m_thread == null || !m_thread.isAlive()) {
      start();
    }
    m_passChangeQueue.offer(new Object[] {session, username, newPassword, oldPassword});
  }

  /**
   * Called by Thread.start()
   */
  public void run() {
    Object [] o;
    IoSession session;
    String username;
    String password;
    String newPassword;
    char l;
    while(m_isRunning) {
      synchronized(m_loginQueue) {
        try {
          if(m_loginQueue.peek() != null) {
            o = m_loginQueue.poll();
            session = (IoSession) o[0];
            l = ((String) o[1]).charAt(0);
            username = ((String) o[1]).substring(1);
            password = (String) o[2];
            this.attemptLogin(session, l, username, password);
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      try {
        Thread.sleep(500);
      } catch (Exception e) {}
     
      synchronized(m_passChangeQueue) {
        try {
          if(m_passChangeQueue.peek() != null) {
            o = m_passChangeQueue.poll();
            session = (IoSession) o[0];
            username = (String) o[1];
            newPassword = (String) o[2];
            password = (String) o[3];
            this.changePass(username, newPassword, password, session);
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      try {
        Thread.sleep(500);
      } catch (Exception e) {}
    }
    m_thread = null;
  }
 
  /**
   * Starts the login manager
   */
  public void start() {
    if(m_thread == null || !m_thread.isAlive()) {
      m_thread = new Thread(this);
      m_isRunning = true;
      m_thread.start();
    }
  }
 
  /**
   * Stops the login manager
   */
  public void stop() {
    m_isRunning = false;
  }
 
  /**
   * Changes the password of a player
   * @param username
   * @param newPassword
   * @param oldPassword
   * @param session
   */
  private void changePass(String username, String newPassword, String oldPassword, IoSession session) {
    m_database = new MySqlManager();
 
    if(m_database.connect(GameServer.getDatabaseHost(), GameServer.getDatabaseUsername(), GameServer.getDatabasePassword())) {
      if(m_database.selectDatabase(GameServer.getDatabaseName())) {
        ResultSet result = m_database.query("SELECT * FROM pn_members WHERE username='" + MySqlManager.parseSQL(username) + "'");
        try {
          if(result.first()){
            // if we got a result, compare their old password to the one we have stored for them
            if(result.getString("password").compareTo(oldPassword) == 0) {
              // old password matches the one on file, therefore they got their old password correct, so it can be changed to their new one
              m_database.query("UPDATE pn_members SET password='" + MySqlManager.parseSQL(newPassword) + "' WHERE username='" + MySqlManager.parseSQL(username) + "'");
              // tell them their password was changed successfully
              session.write("ps");
              return;
            }
          }
        } catch (SQLException e) {
          e.printStackTrace();
        }
        m_database.close();
      }
    }
    // tell them we failed to change their password
    session.write("pe");
  }
 
  /**
   * Logs in a player
   * @param username
   * @param language
   * @param session
   * @param result
   */
  private void login(String username, char language, IoSession session, ResultSet result) {
    //They are not logged in elsewhere, set the current login to the current server
    long time = System.currentTimeMillis();
    /*
     * Attempt to log the player in
     */
    PlayerChar p = getPlayerObject(result);
    p.setLastLoginTime(time);
    p.setTcpSession(session);
    p.setLanguage(Language.values()[Integer.parseInt(String.valueOf(language))]);
    /*
     * Update the database with login information
     */
    m_database.query("UPDATE pn_members SET lastLoginServer='" + MySqlManager.parseSQL(GameServer.getServerName()) + "', lastLoginTime='" + time + "' WHERE username='" + MySqlManager.parseSQL(username) + "'");
    m_database.query("UPDATE pn_members SET lastLoginIP='" + getIp(session) + "' WHERE username='" + MySqlManager.parseSQL(username) + "'");
    m_database.query("UPDATE pn_members SET lastLanguageUsed='" + language + "' WHERE username='" + MySqlManager.parseSQL(username) + "'");
    session.setAttribute("player", p);
    /*
     * Send success packet to player, set their map and add them to a movement service
     */
    this.initialiseClient(p, session);
    /*
     * Add them to the list of players
     */
    TcpProtocolHandler.addPlayer(p);
    UdpProtocolHandler.addPlayer(p);
    GameServer.getInstance().updatePlayerCount();
    System.out.println("INFO: " + username + " logged in.");
  }
 
  /**
   * Sends initial information to the client
   * @param p
   * @param session
   */
  private void initialiseClient(PlayerChar p, IoSession session) {
    session.write("ls" + p.getId() + "," + TimeService.getTime());
    //Add them to the map
    p.setMap(GameServer.getServiceManager().getMovementService().getMapMatrix().getMapByGamePosition(p.getMapX(), p.getMapY()), null);
    //Add them to a movement service
    GameServer.getServiceManager().getMovementService().getMovementManager().addPlayer(p);
    //Send their Pokemon information to them
    p.updateClientParty();
    //Send bag to them
    p.updateClientBag();
    //Send money
    p.updateClientMoney();
    //Send their friend list to them
//    p.updateClientFriends();
    //Send badges
    p.updateClientBadges();
    p.initializeClientSkills();
  }

  /**
   * Returns a playerchar object from a resultset of player data
   * @param data
   * @return
   */
  private PlayerChar getPlayerObject(ResultSet result) {
    try {
      PlayerChar p = new PlayerChar();
      Pokemon [] party = new Pokemon[6];
      PokemonBox[] boxes = new PokemonBox[9];
     
      p.setName(result.getString("username"));
      p.setVisible(true);
      //Set co-ordinates
      p.setX(result.getInt("x"));
      p.setY(result.getInt("y"));
      p.setMapX(result.getInt("mapX"));
      p.setMapY(result.getInt("mapY"));
      p.setId(result.getInt("id"));
      p.setAdminLevel(result.getInt("adminLevel"));
      p.setMuted(result.getBoolean("muted"));
      p.setLastHeal(result.getInt("healX"), result.getInt("healY"), result.getInt("healMapX"), result.getInt("healMapY"));
      p.setSurfing(Boolean.parseBoolean(result.getString("isSurfing")));
      //Set money and skills
      p.setSprite(result.getInt("sprite"));
      p.setMoney(result.getInt("money"));
      p.setHerbalismExp(result.getInt("skHerb"));
      p.setCraftingExp(result.getInt("skCraft"));
      p.setFishingExp(result.getInt("skFish"));
      p.setTrainingExp(result.getInt("skTrain"));
      p.setCoordinatingExp(result.getInt("skCoord"));
      p.setBreedingExp(result.getInt("skBreed"));
      //Retrieve refences to all Pokemon
      int partyId = result.getInt("party");
      ResultSet partyData = m_database.query("SELECT * FROM pn_party WHERE id='" + partyId + "'");
      partyData.first();
     
      ResultSet pokemons = m_database.query("SELECT * FROM pn_pokemon WHERE currentTrainerName='" + p.getName() + "'");
      int boxNumber = 0;
      int boxPosition = 0;
      /* Loop through all Pokemon belonging to this player and add them to their party/box */
      while(pokemons.next()) {
        boolean isParty = false;
        int partyIndex = -1;
        /* Checks if Pokemon is in party */
        for(int i = 0; i < 6; i++) {
          if(partyData.getInt("pokemon" + i) == pokemons.getInt("id")) {
            isParty = true;
            partyIndex = i;
            break;
          }
        }
        /* If the pokemon is in party, add it to party */
        if(isParty) {
          party[partyIndex] = getPokemonObject(pokemons);
        } else {
          /* Else, add it to box if space is available */
          if(boxNumber < 9) {
            /* Avoid null pointers */
            if(boxes[boxNumber] == null)
              boxes[boxNumber] = new PokemonBox();
            if(boxes[boxNumber].getPokemon() == null)
              boxes[boxNumber].setPokemon(new Pokemon[30]);
            /* If there's space in this box, add it to the box */
            if(boxPosition < 30) {
              boxes[boxNumber].setPokemon(boxPosition, getPokemonObject(pokemons));
            } else {
              /* Else open up a new box and add it to box */
              boxPosition = 0;
              boxNumber++;
              if(boxNumber < 9) {
                boxes[boxNumber].setPokemon(new Pokemon[30]);
                boxes[boxNumber].setPokemon(boxPosition, getPokemonObject(pokemons));
              }
            }
            boxPosition++;
          }
        }
      }
      p.setParty(party);
      p.setBoxes(boxes);
     
      //Attach bag
      p.setBag(getBagObject(m_database.query("SELECT * FROM pn_bag WHERE member='" + result.getInt("id") + "'"),p.getId()));

      //Attach badges
      p.generateBadges(result.getString("badges"));
      return p;
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }
 
  /**
   * Returns a Pokemon object based on a set of data
   * @param data
   * @return
   */
  private Pokemon getPokemonObject(ResultSet data) {
    if(data != null) {
      try {
        /*
         * First generate the Pokemons moves
         */
        MoveListEntry [] moves = new MoveListEntry[4];
        moves[0] = (data.getString("move0") != null && !data.getString("move0").equalsIgnoreCase("null") ?
            DataService.getMovesList().getMove(data.getString("move0")) :
              null);
        moves[1] = (data.getString("move1") != null && !data.getString("move1").equalsIgnoreCase("null") ?
            DataService.getMovesList().getMove(data.getString("move1")) :
              null);
        moves[2] = (data.getString("move2") != null && !data.getString("move2").equalsIgnoreCase("null") ?
            DataService.getMovesList().getMove(data.getString("move2")) :
              null);
        moves[3] = (data.getString("move3") != null && !data.getString("move3").equalsIgnoreCase("null") ?
            DataService.getMovesList().getMove(data.getString("move3")) :
              null);
        /*
         * Create the new Pokemon
         */
        Pokemon p = new Pokemon(
            DataService.getBattleMechanics(),
            PokemonSpecies.getDefaultData().getPokemonByName(data.getString("speciesName"))
            ,
            PokemonNature.getNatureByName(data.getString("nature")),
            data.getString("abilityName"),
            data.getString("itemName"),
            data.getInt("gender"),
            data.getInt("level"),
            new int[] {
              data.getInt("ivHP"),
              data.getInt("ivATK"),
              data.getInt("ivDEF"),
              data.getInt("ivSPD"),
              data.getInt("ivSPATK"),
              data.getInt("ivSPDEF")},
            new int[] {
              data.getInt("evHP"),
              data.getInt("evATK"),
              data.getInt("evDEF"),
              data.getInt("evSPD"),
              data.getInt("evSPATK"),
              data.getInt("evSPDEF")},
            moves,
            new int[] {
              data.getInt("ppUp0"),
              data.getInt("ppUp1"),
              data.getInt("ppUp2"),
              data.getInt("ppUp3")
            });
        p.reinitialise();
        /*
         * Set exp, nickname, isShiny and exp gain type
         */
        p.setBaseExp(data.getInt("baseExp"));
        p.setExp(Double.parseDouble(data.getString("exp")));
        p.setName(data.getString("name"));
        p.setHappiness(data.getInt("happiness"));
        p.setShiny(Boolean.parseBoolean(data.getString("isShiny")));
        p.setExpType(ExpTypes.valueOf(data.getString("expType")));
        p.setOriginalTrainer(data.getString("originalTrainerName"));
        p.setDatabaseID(data.getInt("id"));
        p.setDateCaught(data.getString("date"));
        p.setIsFainted(Boolean.parseBoolean(data.getString("isFainted")));
        /*
         * Contest stats (beauty, cute, etc.)
         */
        String [] cstats = data.getString("contestStats").split(",");
        p.setContestStat(0, Integer.parseInt(cstats[0]));
        p.setContestStat(1, Integer.parseInt(cstats[1]));
        p.setContestStat(2, Integer.parseInt(cstats[2]));
        p.setContestStat(3, Integer.parseInt(cstats[3]));
        p.setContestStat(4, Integer.parseInt(cstats[4]));
        /*
         * Sets the stats
         */
        p.calculateStats(true);
        p.setHealth(data.getInt("hp"));
        p.setRawStat(1, data.getInt("atk"));
        p.setRawStat(2, data.getInt("def"));
        p.setRawStat(3, data.getInt("speed"));
        p.setRawStat(4, data.getInt("spATK"));
        p.setRawStat(5, data.getInt("spDEF"));
        /*
         * Sets the pp information
         */
        p.setPp(0, data.getInt("pp0"));
        p.setPp(1, data.getInt("pp1"));
        p.setPp(2, data.getInt("pp2"));
        p.setPp(3, data.getInt("pp3"));
        p.setPpUp(0, data.getInt("ppUp0"));
        p.setPpUp(0, data.getInt("ppUp1"));
        p.setPpUp(0, data.getInt("ppUp2"));
        p.setPpUp(0, data.getInt("ppUp3"));
        return p;
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    return null;
  }
 
  /**
   * Returns a bag object
   * @param data
   * @return
   */
  private Bag getBagObject(ResultSet data, int memberid) {
    try {
      Bag b = new Bag(memberid);
      while(data.next()){
        b.addItem(data.getInt("item"), data.getInt("quantity"));
      }
      return b;
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
   
  }
}
TOP

Related Classes of org.pokenet.server.network.LoginManager

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.