Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/netp2/src/network/Server.cc @ 2945

Last change on this file since 2945 was 2944, checked in by scheusso, 16 years ago

this is another commit for testing purpose
still trying to get network function calls to work (first success)

  • Property svn:eol-style set to native
File size: 12.8 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#include "FunctionCallManager.h"
63#include "packet/FunctionIDs.h"
64
65
66namespace orxonox
67{
68  const unsigned int MAX_FAILURES = 20;
69
70  /**
71  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
72  *
73  */
74  Server::Server() {
75    timeSinceLastUpdate_=0;
76    connection = new ConnectionManager();
77    gamestates_ = new GamestateManager();
78  }
79
80  Server::Server(int port){
81    timeSinceLastUpdate_=0;
82    connection = new ConnectionManager(port);
83    gamestates_ = new GamestateManager();
84  }
85
86  /**
87  * Constructor
88  * @param port Port to listen on
89  * @param bindAddress Address to listen on
90  */
91  Server::Server(int port, const std::string& bindAddress) {
92    timeSinceLastUpdate_=0;
93    connection = new ConnectionManager(port, bindAddress);
94    gamestates_ = new GamestateManager();
95  }
96
97  /**
98  * Constructor
99  * @param port Port to listen on
100  * @param bindAddress Address to listen on
101  */
102  Server::Server(int port, const char *bindAddress) {
103    timeSinceLastUpdate_=0;
104    connection = new ConnectionManager(port, bindAddress);
105    gamestates_ = new GamestateManager();
106  }
107
108  /**
109  * @brief Destructor
110  */
111  Server::~Server(){
112    if(connection)
113      delete connection;
114    if(gamestates_)
115      delete gamestates_;
116  }
117
118  /**
119  * This function opens the server by creating the listener thread
120  */
121  void Server::open() {
122    connection->createListener();
123    return;
124  }
125
126  /**
127  * This function closes the server
128  */
129  void Server::close() {
130    connection->quitListener();
131    return;
132  }
133
134  bool Server::processChat(const std::string& message, unsigned int playerID){
135    ClientInformation *temp = ClientInformation::getBegin();
136    packet::Chat *chat;
137    while(temp){
138      chat = new packet::Chat(message, playerID);
139      chat->setClientID(temp->getID());
140      if(!chat->send())
141        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
142      temp = temp->next();
143    }
144//    COUT(1) << "Player " << playerID << ": " << message << std::endl;
145    return true;
146  }
147
148
149  /**
150  * Run this function once every tick
151  * calls processQueue and updateGamestate
152  * @param time time since last tick
153  */
154  void Server::tick(float time) {
155    processQueue();
156    //this steers our network frequency
157    timeSinceLastUpdate_+=time;
158    if(timeSinceLastUpdate_>=NETWORK_PERIOD){
159      timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
160      gamestates_->processGamestates();
161      updateGamestate();
162      FunctionCallManager::sendCalls();
163    }
164  }
165
166  bool Server::queuePacket(ENetPacket *packet, int clientID){
167    return connection->addPacket(packet, clientID);
168  }
169 
170  /**
171   * @brief: returns ping time to client in milliseconds
172   */
173  unsigned int Server::getPing(unsigned int clientID){
174    assert(ClientInformation::findClient(clientID));
175    return ClientInformation::findClient(clientID)->getRTT();
176  }
177
178  /**
179   * @brief: return packet loss ratio to client (scales from 0 to 1)
180   */
181  double Server::getPacketLoss(unsigned int clientID){
182    assert(ClientInformation::findClient(clientID));
183    return ClientInformation::findClient(clientID)->getPacketLoss();
184  }
185 
186  /**
187  * processes all the packets waiting in the queue
188  */
189  void Server::processQueue() {
190    ENetEvent *event;
191    while(!connection->queueEmpty()){
192      //std::cout << "Client " << clientID << " sent: " << std::endl;
193      //clientID here is a reference to grab clientID from ClientInformation
194      event = connection->getEvent();
195      if(!event)
196        continue;
197      assert(event->type != ENET_EVENT_TYPE_NONE);
198      switch( event->type ) {
199      case ENET_EVENT_TYPE_CONNECT:
200        COUT(3) << "processing event_Type_connect" << std::endl;
201        addClient(event);
202        break;
203      case ENET_EVENT_TYPE_DISCONNECT:
204        if(ClientInformation::findClient(&event->peer->address))
205          disconnectClient(event);
206        break;
207      case ENET_EVENT_TYPE_RECEIVE:
208        if(!processPacket(event->packet, event->peer))
209          COUT(3) << "processing incoming packet failed" << std::endl;
210        break;
211      default:
212        break;
213      }
214      delete event;
215      //if statement to catch case that packetbuffer is empty
216    }
217  }
218
219  /**
220  * takes a new snapshot of the gamestate and sends it to the clients
221  */
222  void Server::updateGamestate() {
223//     if( ClientInformation::getBegin()==NULL )
224      //no client connected
225//       return;
226    gamestates_->update();
227    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
228    //std::cout << "updated gamestate, sending it" << std::endl;
229    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
230    sendGameState();
231    sendObjectDeletes();
232    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
233    //std::cout << "sent gamestate" << std::endl;
234  }
235
236  bool Server::processPacket( ENetPacket *packet, ENetPeer *peer ){
237    packet::Packet *p = packet::Packet::createPacket(packet, peer);
238    return p->process();
239  }
240
241  /**
242  * sends the gamestate
243  */
244  bool Server::sendGameState() {
245    COUT(5) << "Server: starting function sendGameState" << std::endl;
246    ClientInformation *temp = ClientInformation::getBegin();
247    bool added=false;
248    while(temp != NULL){
249      if( !(temp->getSynched()) ){
250        COUT(5) << "Server: not sending gamestate" << std::endl;
251        temp=temp->next();
252        if(!temp)
253          break;
254        //think this works without continue
255        continue;
256      }
257      COUT(4) << "client id: " << temp->getID() << " RTT: " << temp->getRTT() << " loss: " << temp->getPacketLoss() << std::endl;
258      COUT(5) << "Server: doing gamestate gamestate preparation" << std::endl;
259      int gid = temp->getGamestateID(); //get gamestate id
260      int cid = temp->getID(); //get client id
261      COUT(5) << "Server: got acked (gamestate) ID from clientlist: " << gid << std::endl;
262      packet::Gamestate *gs = gamestates_->popGameState(cid);
263      if(gs==NULL){
264        COUT(2) << "Server: could not generate gamestate (NULL from compress)" << std::endl;
265        temp = temp->next();
266        continue;
267      }
268      //std::cout << "adding gamestate" << std::endl;
269      gs->setClientID(cid);
270      if ( !gs->send() ){
271        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
272        temp->addFailure();
273      }else
274        temp->resetFailures();
275      added=true;
276      temp=temp->next();
277      // gs gets automatically deleted by enet callback
278    }
279    return true;
280  }
281
282  bool Server::sendObjectDeletes(){
283    ClientInformation *temp = ClientInformation::getBegin();
284    if( temp == NULL )
285      //no client connected
286      return true;
287    packet::DeleteObjects *del = new packet::DeleteObjects();
288    if(!del->fetchIDs())
289      return true;  //everything ok (no deletes this tick)
290//     COUT(3) << "sending DeleteObjects" << std::endl;
291    while(temp != NULL){
292      if( !(temp->getSynched()) ){
293        COUT(5) << "Server: not sending gamestate" << std::endl;
294        temp=temp->next();
295        continue;
296      }
297      int cid = temp->getID(); //get client id
298      packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
299      assert(cd);
300      cd->setClientID(cid);
301      if ( !cd->send() )
302        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
303      temp=temp->next();
304      // gs gets automatically deleted by enet callback
305    }
306    return true;
307  }
308
309
310  bool Server::addClient(ENetEvent *event){
311    static unsigned int newid=1;
312
313    COUT(2) << "Server: adding client" << std::endl;
314    ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
315    if(!temp){
316      COUT(2) << "Server: could not add client" << std::endl;
317      return false;
318    }
319    /*if(temp==ClientInformation::getBegin()) { //not good if you use anything else than insertBack
320      newid=1;
321    }
322    else
323      newid=temp->prev()->getID()+1;*/
324    temp->setID(newid);
325    temp->setPeer(event->peer);
326
327    // inform all the listeners
328    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
329    while(listener){
330      listener->clientConnected(newid);
331      listener++;
332    }
333
334    newid++;
335
336    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
337    return createClient(temp->getID());
338}
339
340  bool Server::createClient(int clientID){
341    ClientInformation *temp = ClientInformation::findClient(clientID);
342    if(!temp){
343      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
344      return false;
345    }
346    COUT(5) << "Con.Man: creating client id: " << temp->getID() << std::endl;
347   
348    // synchronise class ids
349    connection->syncClassid(temp->getID());
350   
351    // now synchronise functionIDs
352    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
353    bool b = fIDs->send();
354    assert(b);
355   
356    temp->setSynched(true);
357    COUT(4) << "sending welcome" << std::endl;
358    packet::Welcome *w = new packet::Welcome(temp->getID(), temp->getShipID());
359    w->setClientID(temp->getID());
360    b = w->send();
361    assert(b);
362    packet::Gamestate *g = new packet::Gamestate();
363    g->setClientID(temp->getID());
364    b = g->collectData(0);
365    if(!b)
366      return false; //no data for the client
367    b = g->compressData();
368    assert(b);
369    b = g->send();
370    assert(b);
371    return true;
372  }
373
374  bool Server::disconnectClient(ENetEvent *event){
375    COUT(4) << "removing client from list" << std::endl;
376    //return removeClient(head_->findClient(&(peer->address))->getID());
377
378    //boost::recursive_mutex::scoped_lock lock(head_->mutex_);
379    ClientInformation *client = ClientInformation::findClient(&event->peer->address);
380    if(!client)
381      return false;
382    gamestates_->removeClient(client);
383
384// inform all the listeners
385    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
386    while(listener){
387      listener->clientDisconnected(client->getID());
388      listener++;
389    }
390
391    return ClientInformation::removeClient(event->peer);
392  }
393
394  void Server::disconnectClient(int clientID){
395    ClientInformation *client = ClientInformation::findClient(clientID);
396    if(client)
397      disconnectClient(client);
398  }
399  void Server::disconnectClient( ClientInformation *client){
400    connection->disconnectClient(client);
401    gamestates_->removeClient(client);
402  }
403
404  bool Server::chat(const std::string& message){
405      return this->sendChat(message, Host::getPlayerID());
406  }
407
408  bool Server::broadcast(const std::string& message){
409      return this->sendChat(message, CLIENTID_UNKNOWN);
410  }
411
412  bool Server::sendChat(const std::string& message, unsigned int clientID){
413    ClientInformation *temp = ClientInformation::getBegin();
414    packet::Chat *chat;
415    while(temp){
416      chat = new packet::Chat(message, clientID);
417      chat->setClientID(temp->getID());
418      if(!chat->send())
419        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
420      temp = temp->next();
421    }
422//    COUT(1) << "Player " << Host::getPlayerID() << ": " << message << std::endl;
423    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
424      it->incomingChat(message, clientID);
425
426    return true;
427  }
428
429}
Note: See TracBrowser for help on using the repository browser.