Package de.creepsmash.server

Source Code of de.creepsmash.server.Client

/**
   Creep Smash, a multiplayer towerdefence game
   created as a project at the Hochschule fuer
   Technik Stuttgart (University of Applied Science)
   http://www.hft-stuttgart.de
  
   Copyright (C) 2008 by     
    * Andreas Wittig
    * Bernd Hietler
    * Christoph Fritz
    * Fabian Kessel
    * Levin Fritz
    * Nikolaj Langner
    * Philipp Schulte-Hubbert
    * Robert Rapczynski
    * Ron Trautsch
    * Sven Supper
    http://creepsmash.sf.net/

    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 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   
    history:
    - initial version by hft-stuttgart (see above)
    - 2008-2009, changed by creepsmash.de team
    - Jun 2009, updated by ch_f for creepsmash.de
**/


package de.creepsmash.server;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.Logger;

import de.creepsmash.common.IConstants;
import de.creepsmash.common.messages.client.BuildTowerMessage;
import de.creepsmash.common.messages.client.ClientMessage;
import de.creepsmash.common.messages.client.SellTowerMessage;
import de.creepsmash.common.messages.client.UpgradeTowerMessage;
import de.creepsmash.common.messages.server.ErrorMessage;
import de.creepsmash.common.messages.server.ServerMessage;

/**
* This Class represents the instance of a client inside the server-package.
* Every client has a ClientID, is in a GameState and is able to send or to
* receive Messages.
* Adds also calculation of the clients current money that can be used for
* cheating detection.
*
*/
public class Client {

  private int clientID;
  private ClientState clientState;
  private ClientInThread clientInThread;
  private QueueConsumerThread<ServerMessage> clientOutThread;
  private String userName;
  private Socket socket;
  private String mac;
 
  private int anticheatCurrentMoney;
  private int anticheatCurrentIncome;
  private int anticheatTicksPerIncomeInterval;
  private long anticheatLastTickWhereHappendSomething;
  List<String> anticheatTowerId = new ArrayList<String>();
 
  private static Logger clientLogger = Logger.getLogger(Client.class);

  /**
   * Constructor for TestClient, do not use otherwise.
   */
  protected Client() {
  }

  /**
   * Constructor ...
   *
   * @param id
   *            the client's ID is a simple integer.
   * @param socket
   *            the client's socket is a simple client-socket which is used to
   *            connect to the server.
   * @param authenticationService
   *            the AuthenticationService
   */
  public Client(int id, Socket socket,
      AuthenticationService authenticationService) {
   
    this.anticheatCurrentMoney = 0;
    this.anticheatCurrentIncome = IConstants.CREDITS;
    this.anticheatTicksPerIncomeInterval = IConstants.INCOME_TIME / IConstants.TICK_MS;
    this.anticheatLastTickWhereHappendSomething = 0;
   
    this.clientID = id;
    this.socket = socket;

    try {
      OutTranslator outTranslator = new OutTranslator(socket
          .getOutputStream(), id);
      BlockingQueue<QueueMessage<ServerMessage>> outQueue =
        new LinkedBlockingQueue<QueueMessage<ServerMessage>>();
      this.clientOutThread = new QueueConsumerThread<ServerMessage>(outTranslator, outQueue);
      this.clientOutThread.start();
      this.clientInThread = new ClientInThread(socket.getInputStream(), this);
      this.clientInThread.start();

      this.clientState = new AnonymousState(outQueue, this, authenticationService);
    } catch (IOException e) {
      clientLogger.error(
          "Problem with Client constructor in serverpacket.", e);
    }
  }

  /**
   * Receive a message from the client (over the network).
   *
   * @param message
   *            the message, or null if the connection to the client has been
   *            closed.
   */
  public void receive(ClientMessage message) {
    if (message == null) {
      this.clientState = this.clientState.receiveMessage(null);
      this.clientOutThread.interrupt();
      try {
        this.socket.close();
      } catch (IOException e) {
        String socketState;
        if (socket.isClosed()) {
          socketState = "closed";
        } else {
          socketState = "open";
        }
        clientLogger.error("Disconnect client" + this.getClientID()
            + this.getUserName() + "failed" + "socket is "
            + socketState, e);
      }
    } else {
      try {
        message.setClientId(this.getClientID());
        this.clientState = this.clientState.receiveMessage(message);
      } catch (NullPointerException e) {
        clientLogger.fatal(
            "Failed to receice message. Clientstate is: "
                + clientState + " message is: "
                + message.getMessageString(), e);
      }
    }
  }

  /**
   * Sends an object of ServerMessage to the outgoing queue.
   *
   * @param message
   *            Expects an ServerMessage object.
   */
  public void send(ServerMessage message) {
    this.clientState = this.clientState.sendMessage(message);
  }

  /**
   * Instantiates the ErrorHandler for handling Errors occurring in the
   * Client/Server Communication and sends the ErrorMessage.
   *
   * @param type
   *            the type
   * @param msg
   *            the message text
   */
  public void handleError(IConstants.ErrorType type, String msg) {
    ErrorMessage errMsg = new ErrorMessage(type, msg);
    this.send(errMsg);
    clientLogger.error(msg);
  }
  public void disconnect(){
    try {
      this.clientInThread.terminate();
      this.socket.close();
      //this.clientInThread.terminate();
      //this.clientOutThread.interrupt();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  /**
   * Shutdown the server (only called from the ShutdownTD pseudo-client).
   */
  public void stopServer() {

    if (this.socket.getInetAddress().equals(this.socket.getLocalAddress())) {

      this.handleError(IConstants.ErrorType.Error,
          "Server is shutting down. ");
      System.exit(0);
    } else {
      clientLogger
          .error("Somebody tried to shutdown server form a remote host!");
    }
  }

  /**
   * Returns a string with id and userName.
   *
   * @return a string with id and userName.
   */
  @Override
  public String toString() {
    return this.clientID + "/" + this.userName;
  }

  /**
   * Returns the client's ID.
   *
   * @return clientID
   */
  public int getClientID() {
    return this.clientID;
  }

  /**
   * Sets the users name for the client.
   *
   * @param name
   *            Expects a String with the users name.
   */
  public void setUserName(String name) {
    this.userName = name;
  }

  /**
   * Returns the users name.
   *
   * @return String users name
   */
  public String getUserName() {
    return this.userName;
  }
  /**
   * Check the Permission, modulo n function
   *
   * @return String users name
   */
  public boolean getUserPermissionFor(int Permission) {
   
    int modulo = 0;
    modulo = AuthenticationService.getPlayer(this.getUserName()).getPermission() & Permission;
   
    if (modulo == 0){
      return false;
    }else{
      return true;
    }
   
  }
  /**
   * Wenn users socket closed ist,
   * dann Killt alle Threads und liefert
   * false zuruck, sonst true
   *
   * @return boolean
   */
  public boolean check() {
    if (this.socket.isClosed() ||
        !this.clientInThread.isAlive() ||
        !this.clientOutThread.isAlive()) {
      try {
        this.socket.close();
        this.clientInThread.terminate();
        this.clientOutThread.interrupt();
      } catch(Exception e) {
       
      }
      return false;
    }
    return true;
  }

  public String getIPAddress() {
    return this.socket.getInetAddress().toString().replaceAll("/", "");
  }

  /**
   * @return the mac
   */
  public String getMACAddress() {
    return mac;
  }

  /**
   * @param mac the mac to set
   */
  public void setMACAddress(String mac) {
    this.mac = mac;
  }

 
  /*
   * Anticheat stuff starts here,
   * could be used in the handlers of RunningGameState
   */
 
  /**
   * Get the clients calculated current money.
   *
   * The server doesn't get a message if a creep walks through a players
   * game context (map). So it's purposed that all incoming creeps are getting killed.
   * This leads to a error.
   *
   * So bear in mind that you have to add for example 2* IConstants.LIVE * bounty of the
   * best creeps sent * the number of alive opponents * 2. So you can be sure that if
   * this player gets over this amount of money, he's definitely cheating!
   *
   * This is a ugly approximation!
   *
   * Possible solution:
   *  - Every client sends a message if a creep crosses the context (map)
   *  - Calculate the game on the server-side
   * 
   *  If this return value plus tolerance is less than zero,
   *  this client is pretty sure cheating!
   * 
   *  @param atTick the current tick-time
   *  @return money the client has at this tick-time (with error!)
   *
   */
  public int anticheat_getNotExaktCurrentMoney(long atTick) {
    anticheat_updateMoney(atTick);
    return anticheatCurrentMoney;
  }
 
 
  /**
   * Update money of this client.
   *
   * @param tick the current tick-time
   */
  private void anticheat_updateMoney(long tick) {
    int numberOfHappenedRounds = (int)(((tick /*+ IConstants.USER_ACTION_DELAY*/) - this.anticheatLastTickWhereHappendSomething)
                   / IConstants.INCOME_TIME);
    this.anticheatLastTickWhereHappendSomething = tick;
   
    this.anticheatCurrentMoney += this.anticheatCurrentIncome * numberOfHappenedRounds;
  }
 
  /**
   * Handles towers being built.
   *
   * Creates a new tower by id in a list. So later the tower can be
   * upgraded or sold and we know the price.
   * It also decreases the currentMoney Value.
   *
   * @param m BuildTowerMessage to extract type of tower
   * @param id Identification Number of the new generated tower
   *
   */
  public void anticheat_TowerBuilt(BuildTowerMessage m, int id) {
    anticheatTowerId.add(id, IConstants.Towers.valueOf(IConstants.Towers.class, m.getTowerType()).getName());
    anticheatCurrentMoney -= IConstants.Towers.valueOf(IConstants.Towers.class, anticheatTowerId.get(id)).getPrice();
    clientLogger.warn(anticheatCurrentMoney);
  }
 
  /**
   * Handles towers being sold.
   *
   * @param m SellTowerMessage
   *
   */
  public void anticheat_TowerSold(SellTowerMessage m) {
    anticheatCurrentMoney -= (int) IConstants.Towers.valueOf
      (
          IConstants.Towers.class,
          anticheatTowerId.get(m.getTowerId())
      ).getPrice() * 0.75;
  }
 
  /**
   * Handles towers being upgraded.
   *
   * @param m UpgradeTowerMessage
   */
  public void anticheat_TowerUpgraded(UpgradeTowerMessage m) {
   
    String nameOfNextTower = IConstants.Towers.valueOf(
        IConstants.Towers.class, anticheatTowerId.get(m.getTowerId()))
        .getNext().getName();
   
    anticheatTowerId.set(m.getTowerId(), nameOfNextTower );
   
    anticheatCurrentMoney -= IConstants.Towers.valueOf(
        IConstants.Towers.class, anticheatTowerId.get(m.getTowerId()))
        .getNext().getPrice();
  }
 
  /**
   * Handles creeps this client sent.
   *
   * It decreases the anticheatCurrentMoney with the price of the creep
   * from this client and increases anticheatCurrentIncome according to the
   * type of creep.
   *
   * @param creepType
   */
  public void anticheat_sentThisCreep(String creepType, long atTick) {
    anticheat_updateMoney(atTick);
    anticheatCurrentMoney -= IConstants.Creeps.valueOf(IConstants.Creeps.class, creepType).getPrice();
    anticheatCurrentIncome += IConstants.Creeps.valueOf(IConstants.Creeps.class, creepType).getIncome();
  }
 
  /**
   * Handles received creeps.
   *
   * Bear in mind that this function is called for the right client!
   *
   * Every smashed creep gives money.
   *
   * This increases the anticheatCurrentMoney according to the
   * type of creep. It is purposed that the client always kills all enemies
   * an gets the bounty of it. Because the server doesn't know when a creep walks through the
   * client's game context (map).
   * This leads to a small error in the calculation.
   *
   * @param creepType
   */
  public void anticheat_receivedThisCreep(String creepType) {
    this.anticheatCurrentMoney = IConstants.Creeps.valueOf(IConstants.Creeps.class, creepType).getBounty();
  }

}
TOP

Related Classes of de.creepsmash.server.Client

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.