Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/questsystem5/src/network/Server.cc @ 3008

Last change on this file since 3008 was 2908, checked in by dafrick, 16 years ago

Reverted to revision 2906 (because I'm too stupid to merge correctly, 2nd try will follow shortly. ;))

  • 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.