Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/network/Server.cc @ 2872

Last change on this file since 2872 was 2773, checked in by rgrieder, 15 years ago

Removed all enet and boost includes from header files in the network library.

  • Reduces dependencies
  • Minimises problems with windows.h
  • Speeds up the compiling process a little bit (probably negligible)
  • Also removes ugly WIN32_LEAN_AND_MEAN declarations before every enet.h include in the network library.

Removed windows.h header from util/Sleep.h by adding Sleep.cc

  • Property svn:eol-style set to native
File size: 12.5 KB
RevLine 
[1502]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Oliver Scheuss, (C) 2007
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29//
30// C++ Implementation: Server
31//
32// Description:
33//
34//
35// Author:  Oliver Scheuss, (C) 2007
36//
37// Copyright: See COPYING file that comes with this distribution
38//
39//
40
41#include "Server.h"
42
[2773]43#include <enet/enet.h>
[1502]44#include <iostream>
[1755]45#include <cassert>
[1502]46
47
48#include "ConnectionManager.h"
[2087]49#include "ClientConnectionListener.h"
[1735]50#include "GamestateManager.h"
[1502]51#include "ClientInformation.h"
52#include "util/Sleep.h"
[1534]53#include "core/ConsoleCommand.h"
[1752]54#include "core/CoreIncludes.h"
[1747]55#include "core/Iterator.h"
[1735]56#include "packet/Chat.h"
57#include "packet/Packet.h"
58#include "packet/Welcome.h"
[1907]59#include "packet/DeleteObjects.h"
[2773]60#include "util/Convert.h"
[2087]61#include "ChatListener.h"
[1502]62
[2171]63namespace orxonox
[1502]64{
[2087]65  const unsigned int MAX_FAILURES = 20;
[1747]66
[1502]67  /**
68  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
69  *
70  */
71  Server::Server() {
72    timeSinceLastUpdate_=0;
[1735]73    connection = new ConnectionManager();
74    gamestates_ = new GamestateManager();
[1502]75  }
[1747]76
[1502]77  Server::Server(int port){
78    timeSinceLastUpdate_=0;
[1735]79    connection = new ConnectionManager(port);
80    gamestates_ = new GamestateManager();
[1502]81  }
82
83  /**
84  * Constructor
85  * @param port Port to listen on
86  * @param bindAddress Address to listen on
87  */
[2087]88  Server::Server(int port, const std::string& bindAddress) {
[1502]89    timeSinceLastUpdate_=0;
[1735]90    connection = new ConnectionManager(port, bindAddress);
91    gamestates_ = new GamestateManager();
[1502]92  }
93
94  /**
95  * Constructor
96  * @param port Port to listen on
97  * @param bindAddress Address to listen on
98  */
99  Server::Server(int port, const char *bindAddress) {
100    timeSinceLastUpdate_=0;
[1735]101    connection = new ConnectionManager(port, bindAddress);
102    gamestates_ = new GamestateManager();
[1502]103  }
[2087]104
[1907]105  /**
106  * @brief Destructor
107  */
108  Server::~Server(){
109    if(connection)
110      delete connection;
111    if(gamestates_)
112      delete gamestates_;
113  }
[1502]114
115  /**
116  * This function opens the server by creating the listener thread
117  */
118  void Server::open() {
119    connection->createListener();
120    return;
121  }
122
123  /**
124  * This function closes the server
125  */
126  void Server::close() {
127    connection->quitListener();
128    return;
129  }
130
[2087]131  bool Server::processChat(const std::string& message, unsigned int playerID){
[1735]132    ClientInformation *temp = ClientInformation::getBegin();
[1907]133    packet::Chat *chat;
[1735]134    while(temp){
[1907]135      chat = new packet::Chat(message, playerID);
[1735]136      chat->setClientID(temp->getID());
137      if(!chat->send())
138        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
[1907]139      temp = temp->next();
[1735]140    }
[2087]141//    COUT(1) << "Player " << playerID << ": " << message << std::endl;
[1907]142    return true;
[1502]143  }
144
145
146  /**
147  * Run this function once every tick
148  * calls processQueue and updateGamestate
149  * @param time time since last tick
150  */
151  void Server::tick(float time) {
152    processQueue();
153    //this steers our network frequency
154    timeSinceLastUpdate_+=time;
[2087]155    if(timeSinceLastUpdate_>=NETWORK_PERIOD){
156      timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
[1735]157      gamestates_->processGamestates();
[1502]158      updateGamestate();
159    }
160  }
[1747]161
[1735]162  bool Server::queuePacket(ENetPacket *packet, int clientID){
163    return connection->addPacket(packet, clientID);
164  }
[2087]165 
166  /**
167   * @brief: returns ping time to client in milliseconds
168   */
169  unsigned int Server::getPing(unsigned int clientID){
170    assert(ClientInformation::findClient(clientID));
171    return ClientInformation::findClient(clientID)->getRTT();
172  }
[1502]173
174  /**
[2087]175   * @brief: return packet loss ratio to client (scales from 0 to 1)
176   */
177  double Server::getPacketLoss(unsigned int clientID){
178    assert(ClientInformation::findClient(clientID));
179    return ClientInformation::findClient(clientID)->getPacketLoss();
180  }
181 
182  /**
[1502]183  * processes all the packets waiting in the queue
184  */
185  void Server::processQueue() {
186    ENetEvent *event;
187    while(!connection->queueEmpty()){
188      //std::cout << "Client " << clientID << " sent: " << std::endl;
189      //clientID here is a reference to grab clientID from ClientInformation
190      event = connection->getEvent();
191      if(!event)
192        continue;
193      assert(event->type != ENET_EVENT_TYPE_NONE);
194      switch( event->type ) {
195      case ENET_EVENT_TYPE_CONNECT:
196        COUT(3) << "processing event_Type_connect" << std::endl;
197        addClient(event);
198        break;
199      case ENET_EVENT_TYPE_DISCONNECT:
[1735]200        if(ClientInformation::findClient(&event->peer->address))
[1502]201          disconnectClient(event);
202        break;
203      case ENET_EVENT_TYPE_RECEIVE:
[1735]204        if(!processPacket(event->packet, event->peer))
205          COUT(3) << "processing incoming packet failed" << std::endl;
[1502]206        break;
[1556]207      default:
208        break;
[1502]209      }
210      delete event;
211      //if statement to catch case that packetbuffer is empty
212    }
213  }
214
215  /**
216  * takes a new snapshot of the gamestate and sends it to the clients
217  */
218  void Server::updateGamestate() {
[2662]219//     if( ClientInformation::getBegin()==NULL )
220      //no client connected
221//       return;
[1735]222    gamestates_->update();
[1534]223    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
[1502]224    //std::cout << "updated gamestate, sending it" << std::endl;
225    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
226    sendGameState();
[1907]227    sendObjectDeletes();
[1534]228    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
[1502]229    //std::cout << "sent gamestate" << std::endl;
230  }
231
[1735]232  bool Server::processPacket( ENetPacket *packet, ENetPeer *peer ){
233    packet::Packet *p = packet::Packet::createPacket(packet, peer);
234    return p->process();
235  }
[1747]236
[1502]237  /**
238  * sends the gamestate
239  */
240  bool Server::sendGameState() {
241    COUT(5) << "Server: starting function sendGameState" << std::endl;
[1735]242    ClientInformation *temp = ClientInformation::getBegin();
[1502]243    bool added=false;
244    while(temp != NULL){
245      if( !(temp->getSynched()) ){
246        COUT(5) << "Server: not sending gamestate" << std::endl;
247        temp=temp->next();
[1735]248        if(!temp)
249          break;
[1502]250        //think this works without continue
251        continue;
252      }
[1534]253      COUT(4) << "client id: " << temp->getID() << " RTT: " << temp->getRTT() << " loss: " << temp->getPacketLoss() << std::endl;
[1502]254      COUT(5) << "Server: doing gamestate gamestate preparation" << std::endl;
255      int gid = temp->getGamestateID(); //get gamestate id
256      int cid = temp->getID(); //get client id
257      COUT(5) << "Server: got acked (gamestate) ID from clientlist: " << gid << std::endl;
[1735]258      packet::Gamestate *gs = gamestates_->popGameState(cid);
[1502]259      if(gs==NULL){
260        COUT(2) << "Server: could not generate gamestate (NULL from compress)" << std::endl;
[2087]261        temp = temp->next();
[1502]262        continue;
263      }
264      //std::cout << "adding gamestate" << std::endl;
[1735]265      gs->setClientID(cid);
266      if ( !gs->send() ){
[1747]267        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
[1502]268        temp->addFailure();
269      }else
270        temp->resetFailures();
271      added=true;
272      temp=temp->next();
[1735]273      // gs gets automatically deleted by enet callback
[1502]274    }
275    return true;
276  }
[1747]277
[1907]278  bool Server::sendObjectDeletes(){
279    ClientInformation *temp = ClientInformation::getBegin();
[2662]280    if( temp == NULL )
281      //no client connected
282      return true;
[1907]283    packet::DeleteObjects *del = new packet::DeleteObjects();
284    if(!del->fetchIDs())
285      return true;  //everything ok (no deletes this tick)
286//     COUT(3) << "sending DeleteObjects" << std::endl;
287    while(temp != NULL){
288      if( !(temp->getSynched()) ){
289        COUT(5) << "Server: not sending gamestate" << std::endl;
290        temp=temp->next();
291        continue;
292      }
293      int cid = temp->getID(); //get client id
294      packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
295      assert(cd);
296      cd->setClientID(cid);
297      if ( !cd->send() )
298        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
299      temp=temp->next();
300      // gs gets automatically deleted by enet callback
301    }
302    return true;
303  }
[1747]304
[1907]305
[1502]306  bool Server::addClient(ENetEvent *event){
[2087]307    static unsigned int newid=1;
308
309    COUT(2) << "Server: adding client" << std::endl;
[1735]310    ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
[1502]311    if(!temp){
312      COUT(2) << "Server: could not add client" << std::endl;
313      return false;
314    }
[2087]315    /*if(temp==ClientInformation::getBegin()) { //not good if you use anything else than insertBack
316      newid=1;
[1502]317    }
318    else
[2087]319      newid=temp->prev()->getID()+1;*/
320    temp->setID(newid);
[1502]321    temp->setPeer(event->peer);
[2087]322
323    // inform all the listeners
[2171]324    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
[2087]325    while(listener){
326      listener->clientConnected(newid);
327      listener++;
328    }
329
330    newid++;
331
[1502]332    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
333    return createClient(temp->getID());
[2087]334}
[1747]335
[1502]336  bool Server::createClient(int clientID){
[1735]337    ClientInformation *temp = ClientInformation::findClient(clientID);
[1502]338    if(!temp){
339      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
340      return false;
341    }
342    COUT(4) << "Con.Man: creating client id: " << temp->getID() << std::endl;
343    connection->syncClassid(temp->getID());
344    temp->setSynched(true);
345    COUT(3) << "sending welcome" << std::endl;
[1735]346    packet::Welcome *w = new packet::Welcome(temp->getID(), temp->getShipID());
347    w->setClientID(temp->getID());
[1907]348    bool b = w->send();
349    assert(b);
[1751]350    packet::Gamestate *g = new packet::Gamestate();
351    g->setClientID(temp->getID());
[1907]352    b = g->collectData(0);
[2087]353    if(!b)
354      return false; //no data for the client
[1907]355    b = g->compressData();
356    assert(b);
357    b = g->send();
358    assert(b);
[1502]359    return true;
360  }
[1747]361
[1502]362  bool Server::disconnectClient(ENetEvent *event){
363    COUT(4) << "removing client from list" << std::endl;
364    //return removeClient(head_->findClient(&(peer->address))->getID());
[1747]365
[1502]366    //boost::recursive_mutex::scoped_lock lock(head_->mutex_);
[1735]367    ClientInformation *client = ClientInformation::findClient(&event->peer->address);
[1502]368    if(!client)
369      return false;
[1751]370    gamestates_->removeClient(client);
[2087]371
372// inform all the listeners
[2171]373    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
[2087]374    while(listener){
375      listener->clientDisconnected(client->getID());
376      listener++;
[1502]377    }
[2087]378
379    return ClientInformation::removeClient(event->peer);
[1502]380  }
381
382  void Server::disconnectClient(int clientID){
[1735]383    ClientInformation *client = ClientInformation::findClient(clientID);
[1502]384    if(client)
385      disconnectClient(client);
386  }
387  void Server::disconnectClient( ClientInformation *client){
388    connection->disconnectClient(client);
[1735]389    gamestates_->removeClient(client);
[1502]390  }
[2087]391
392  bool Server::chat(const std::string& message){
393      return this->sendChat(message, Host::getPlayerID());
394  }
395
396  bool Server::broadcast(const std::string& message){
397      return this->sendChat(message, CLIENTID_UNKNOWN);
398  }
399
400  bool Server::sendChat(const std::string& message, unsigned int clientID){
[1907]401    ClientInformation *temp = ClientInformation::getBegin();
402    packet::Chat *chat;
403    while(temp){
[2087]404      chat = new packet::Chat(message, clientID);
[1907]405      chat->setClientID(temp->getID());
406      if(!chat->send())
407        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
408      temp = temp->next();
409    }
[2087]410//    COUT(1) << "Player " << Host::getPlayerID() << ": " << message << std::endl;
[2171]411    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
[2087]412      it->incomingChat(message, clientID);
413
[1907]414    return true;
415  }
[1747]416
[1502]417}
Note: See TracBrowser for help on using the repository browser.