Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2776 was 2773, checked in by rgrieder, 16 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
Line 
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
43#include <enet/enet.h>
44#include <iostream>
45#include <cassert>
46
47
48#include "ConnectionManager.h"
49#include "ClientConnectionListener.h"
50#include "GamestateManager.h"
51#include "ClientInformation.h"
52#include "util/Sleep.h"
53#include "core/ConsoleCommand.h"
54#include "core/CoreIncludes.h"
55#include "core/Iterator.h"
56#include "packet/Chat.h"
57#include "packet/Packet.h"
58#include "packet/Welcome.h"
59#include "packet/DeleteObjects.h"
60#include "util/Convert.h"
61#include "ChatListener.h"
62
63namespace orxonox
64{
65  const unsigned int MAX_FAILURES = 20;
66
67  /**
68  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
69  *
70  */
71  Server::Server() {
72    timeSinceLastUpdate_=0;
73    connection = new ConnectionManager();
74    gamestates_ = new GamestateManager();
75  }
76
77  Server::Server(int port){
78    timeSinceLastUpdate_=0;
79    connection = new ConnectionManager(port);
80    gamestates_ = new GamestateManager();
81  }
82
83  /**
84  * Constructor
85  * @param port Port to listen on
86  * @param bindAddress Address to listen on
87  */
88  Server::Server(int port, const std::string& bindAddress) {
89    timeSinceLastUpdate_=0;
90    connection = new ConnectionManager(port, bindAddress);
91    gamestates_ = new GamestateManager();
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;
101    connection = new ConnectionManager(port, bindAddress);
102    gamestates_ = new GamestateManager();
103  }
104
105  /**
106  * @brief Destructor
107  */
108  Server::~Server(){
109    if(connection)
110      delete connection;
111    if(gamestates_)
112      delete gamestates_;
113  }
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
131  bool Server::processChat(const std::string& message, unsigned int playerID){
132    ClientInformation *temp = ClientInformation::getBegin();
133    packet::Chat *chat;
134    while(temp){
135      chat = new packet::Chat(message, playerID);
136      chat->setClientID(temp->getID());
137      if(!chat->send())
138        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
139      temp = temp->next();
140    }
141//    COUT(1) << "Player " << playerID << ": " << message << std::endl;
142    return true;
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;
155    if(timeSinceLastUpdate_>=NETWORK_PERIOD){
156      timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
157      gamestates_->processGamestates();
158      updateGamestate();
159    }
160  }
161
162  bool Server::queuePacket(ENetPacket *packet, int clientID){
163    return connection->addPacket(packet, clientID);
164  }
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  }
173
174  /**
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  /**
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:
200        if(ClientInformation::findClient(&event->peer->address))
201          disconnectClient(event);
202        break;
203      case ENET_EVENT_TYPE_RECEIVE:
204        if(!processPacket(event->packet, event->peer))
205          COUT(3) << "processing incoming packet failed" << std::endl;
206        break;
207      default:
208        break;
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() {
219//     if( ClientInformation::getBegin()==NULL )
220      //no client connected
221//       return;
222    gamestates_->update();
223    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
224    //std::cout << "updated gamestate, sending it" << std::endl;
225    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
226    sendGameState();
227    sendObjectDeletes();
228    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
229    //std::cout << "sent gamestate" << std::endl;
230  }
231
232  bool Server::processPacket( ENetPacket *packet, ENetPeer *peer ){
233    packet::Packet *p = packet::Packet::createPacket(packet, peer);
234    return p->process();
235  }
236
237  /**
238  * sends the gamestate
239  */
240  bool Server::sendGameState() {
241    COUT(5) << "Server: starting function sendGameState" << std::endl;
242    ClientInformation *temp = ClientInformation::getBegin();
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();
248        if(!temp)
249          break;
250        //think this works without continue
251        continue;
252      }
253      COUT(4) << "client id: " << temp->getID() << " RTT: " << temp->getRTT() << " loss: " << temp->getPacketLoss() << std::endl;
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;
258      packet::Gamestate *gs = gamestates_->popGameState(cid);
259      if(gs==NULL){
260        COUT(2) << "Server: could not generate gamestate (NULL from compress)" << std::endl;
261        temp = temp->next();
262        continue;
263      }
264      //std::cout << "adding gamestate" << std::endl;
265      gs->setClientID(cid);
266      if ( !gs->send() ){
267        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
268        temp->addFailure();
269      }else
270        temp->resetFailures();
271      added=true;
272      temp=temp->next();
273      // gs gets automatically deleted by enet callback
274    }
275    return true;
276  }
277
278  bool Server::sendObjectDeletes(){
279    ClientInformation *temp = ClientInformation::getBegin();
280    if( temp == NULL )
281      //no client connected
282      return true;
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  }
304
305
306  bool Server::addClient(ENetEvent *event){
307    static unsigned int newid=1;
308
309    COUT(2) << "Server: adding client" << std::endl;
310    ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
311    if(!temp){
312      COUT(2) << "Server: could not add client" << std::endl;
313      return false;
314    }
315    /*if(temp==ClientInformation::getBegin()) { //not good if you use anything else than insertBack
316      newid=1;
317    }
318    else
319      newid=temp->prev()->getID()+1;*/
320    temp->setID(newid);
321    temp->setPeer(event->peer);
322
323    // inform all the listeners
324    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
325    while(listener){
326      listener->clientConnected(newid);
327      listener++;
328    }
329
330    newid++;
331
332    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
333    return createClient(temp->getID());
334}
335
336  bool Server::createClient(int clientID){
337    ClientInformation *temp = ClientInformation::findClient(clientID);
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;
346    packet::Welcome *w = new packet::Welcome(temp->getID(), temp->getShipID());
347    w->setClientID(temp->getID());
348    bool b = w->send();
349    assert(b);
350    packet::Gamestate *g = new packet::Gamestate();
351    g->setClientID(temp->getID());
352    b = g->collectData(0);
353    if(!b)
354      return false; //no data for the client
355    b = g->compressData();
356    assert(b);
357    b = g->send();
358    assert(b);
359    return true;
360  }
361
362  bool Server::disconnectClient(ENetEvent *event){
363    COUT(4) << "removing client from list" << std::endl;
364    //return removeClient(head_->findClient(&(peer->address))->getID());
365
366    //boost::recursive_mutex::scoped_lock lock(head_->mutex_);
367    ClientInformation *client = ClientInformation::findClient(&event->peer->address);
368    if(!client)
369      return false;
370    gamestates_->removeClient(client);
371
372// inform all the listeners
373    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
374    while(listener){
375      listener->clientDisconnected(client->getID());
376      listener++;
377    }
378
379    return ClientInformation::removeClient(event->peer);
380  }
381
382  void Server::disconnectClient(int clientID){
383    ClientInformation *client = ClientInformation::findClient(clientID);
384    if(client)
385      disconnectClient(client);
386  }
387  void Server::disconnectClient( ClientInformation *client){
388    connection->disconnectClient(client);
389    gamestates_->removeClient(client);
390  }
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){
401    ClientInformation *temp = ClientInformation::getBegin();
402    packet::Chat *chat;
403    while(temp){
404      chat = new packet::Chat(message, clientID);
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    }
410//    COUT(1) << "Player " << Host::getPlayerID() << ": " << message << std::endl;
411    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
412      it->incomingChat(message, clientID);
413
414    return true;
415  }
416
417}
Note: See TracBrowser for help on using the repository browser.