Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/network/Server.cc @ 8808

Last change on this file since 8808 was 8807, checked in by landauf, 13 years ago

Replaced COUT with orxout in network library. Tried to set levels and contexts in a more or less useful way, but not really optimized. Used contexts network, packets, and master_server.
Please use endl instead of \n in the future (@smerkli) ;)

  • Property svn:eol-style set to native
File size: 13.9 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
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#define WIN32_LEAN_AND_MEAN
44#include <enet/enet.h>
45#include <cassert>
46#include <string>
47
48#include "util/Clock.h"
49#include "util/Output.h"
50#include "core/ObjectList.h"
51#include "core/command/Executor.h"
52#include "packet/Chat.h"
53#include "packet/ClassID.h"
54#include "packet/DeleteObjects.h"
55#include "packet/FunctionIDs.h"
56#include "packet/Gamestate.h"
57#include "packet/Welcome.h"
58#include "ChatListener.h"
59// #include "ClientInformation.h"
60#include "FunctionCallManager.h"
61#include "GamestateManager.h"
62#include "WANDiscovery.h"
63
64namespace orxonox
65{
66  const unsigned int MAX_FAILURES = 20;
67
68  /**
69  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
70  *
71  */
72  Server::Server()
73  {
74    this->timeSinceLastUpdate_=0;
75  }
76
77  Server::Server(int port)
78  {
79    this->setPort( port );
80    this->timeSinceLastUpdate_=0;
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  {
90    this->setPort( port );
91    this->setBindAddress( bindAddress );
92    this->timeSinceLastUpdate_=0;
93  }
94
95  /**
96  * @brief Destructor
97  */
98  Server::~Server()
99  {
100  }
101
102
103  /** helper that connects to the master server */
104  void Server::helper_ConnectToMasterserver()
105  {
106//     WANDiscovery::getInstance().msc.sendRequest( MSPROTO_GAME_SERVER " "
107//       MSPROTO_REGISTER_SERVER );
108  }
109
110  /**
111  * This function opens the server by creating the listener thread
112  */
113  void Server::open()
114  {
115    Host::setActive(true);
116    orxout(verbose, context::network) << "opening server" << endl;
117    this->openListener();
118   
119    /* make discoverable on LAN */
120    LANDiscoverable::setActivity(true);
121
122    /* make discoverable on WAN */
123    WANDiscoverable::setActivity(true);
124    /* TODO this needs to be optional, we need a switch from the UI to
125     * enable/disable this
126     */
127//     helper_ConnectToMasterserver();
128
129    /* done */
130    return;
131  }
132
133  /**
134  * This function closes the server
135  */
136  void Server::close()
137  {
138    Host::setActive(false);
139    orxout(verbose, context::network) << "closing server" << endl;
140    this->disconnectClients();
141    this->closeListener();
142
143    /* tell master server we're closing */
144    orxout(internal_info, context::network) << "disconnecting." << endl;
145    WANDiscoverable::setActivity(false);   
146    orxout(internal_info, context::network) << "disconnecting done" << endl;
147
148    LANDiscoverable::setActivity(false);
149    return;
150  }
151
152  bool Server::processChat(const std::string& message, unsigned int playerID)
153  {
154//     ClientInformation *temp = ClientInformation::getBegin();
155    packet::Chat *chat;
156//     while(temp){
157    chat = new packet::Chat(message, playerID);
158    chat->setPeerID(NETWORK_PEER_ID_BROADCAST);
159    chat->send( static_cast<Host*>(this) );
160//         orxout(internal_warning, context::network) << "could not send Chat message to client ID: " << temp->getID() << endl;
161//       temp = temp->next();
162//     }
163//    orxout(message) << "Player " << playerID << ": " << message << endl;
164    return true;
165  }
166
167
168  /* handle incoming data */
169  int rephandler( char *addr, ENetEvent *ev )
170  { 
171    /* reply to pings */
172    if( !strncmp( (char *)ev->packet->data, MSPROTO_PING_GAMESERVER, 
173      MSPROTO_PING_GAMESERVER_LEN ) )
174      //this->msc.sendRequest( MSPROTO_ACK );
175      /* NOTE implement this after pollForReply
176       * reimplementation
177       */
178      return 0;
179
180    /* done handling, return all ok code 0 */
181    return 0;
182  }
183
184  void Server::helper_HandleMasterServerRequests()
185  { 
186    /* poll the master server for replies and see whether something
187     * has to be done or changed.
188     */
189    //WANDiscovery::getInstance().msc.pollForReply( rhandler, 10 );
190  }
191
192  /**
193  * Run this function once every tick
194  * calls processQueue and updateGamestate
195  * @param time time since last tick
196  */
197  void Server::update(const Clock& time)
198  {
199    // receive incoming packets
200    Connection::processQueue();
201
202    // receive and process incoming discovery packets
203    LANDiscoverable::update();
204   
205    // receive and process requests from master server
206    /* todo */
207    //helper_HandleMasterServerRequests();
208
209    if ( GamestateManager::hasPeers() )
210    {
211      // process incoming gamestates
212      GamestateManager::processGamestates();
213      FunctionCallManager::processBufferedFunctionCalls();
214
215      // send function calls to clients
216      FunctionCallManager::sendCalls( static_cast<Host*>(this) );
217
218      //this steers our network frequency
219      timeSinceLastUpdate_+=time.getDeltaTime();
220      if(timeSinceLastUpdate_>=NETWORK_PERIOD)
221      {
222        timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
223        updateGamestate();
224      }
225//       sendPackets(); // flush the enet queue
226    }
227  }
228
229  void Server::queuePacket(ENetPacket *packet, int clientID, uint8_t channelID)
230  {
231    ServerConnection::addPacket(packet, clientID, channelID);
232  }
233
234  /**
235   * @brief: returns ping time to client in milliseconds
236   */
237  unsigned int Server::getRTT(unsigned int clientID)
238  {
239//     assert(ClientInformation::findClient(clientID));
240//     return ClientInformation::findClient(clientID)->getRTT();
241    // TODO: reimplement
242    return 0;
243  }
244
245  void Server::printRTT()
246  {
247//     for( ClientInformation* temp=ClientInformation::getBegin(); temp!=0; temp=temp->next() )
248//       orxout(message) << "Round trip time to client with ID: " << temp->getID() << " is " << temp->getRTT() << " ms" << endl;
249  }
250
251  /**
252   * @brief: return packet loss ratio to client (scales from 0 to 1)
253   */
254  float Server::getPacketLoss(unsigned int clientID)
255  {
256//     assert(ClientInformation::findClient(clientID));
257//     return ClientInformation::findClient(clientID)->getPacketLoss();
258    return 0.;
259  }
260
261  /**
262  * takes a new snapshot of the gamestate and sends it to the clients
263  */
264  void Server::updateGamestate()
265  {
266    if( this->clientIDs_.size()==0 )
267      //no client connected
268      return;
269    GamestateManager::update();
270//     orxout(verbose_more, context::network) << "Server: one gamestate update complete, goig to sendGameState" << endl;
271    //orxout(verbose_more, context::network) << "updated gamestate, sending it" << endl;
272    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
273    sendGameStates();
274    sendObjectDeletes();
275//     orxout(verbose_more, context::network) << "Server: one sendGameState turn complete, repeat in next tick" << endl;
276    //orxout(verbose_more, context::network) << "sent gamestate" << endl;
277  }
278
279  /**
280  * sends the current gamestate to all peers
281  */
282  bool Server::sendGameStates()
283  {
284    std::vector<packet::Gamestate*> gamestates = GamestateManager::getGamestates();
285    std::vector<packet::Gamestate*>::iterator it;
286    for( it = gamestates.begin(); it != gamestates.end(); ++it )
287    {
288      (*it)->send(static_cast<Host*>(this));
289    }
290    return true;
291  }
292
293
294  bool Server::sendObjectDeletes()
295  {
296//     ClientInformation *temp = ClientInformation::getBegin();
297//     if( temp == NULL )
298      //no client connected
299    if( this->clientIDs_.size()==0 )
300      return true;
301    packet::DeleteObjects *del = new packet::DeleteObjects();
302    if(!del->fetchIDs())
303    {
304      delete del;
305      return true;  //everything ok (no deletes this tick)
306    }
307//     orxout(verbose, context::network) << "sending DeleteObjects" << endl;
308//     while(temp != NULL){
309//       if( !(temp->getSynched()) )
310//       {
311//         orxout(verbose_more, context::network) << "Server: not sending gamestate" << endl;
312//         temp=temp->next();
313//         continue;
314//       }
315//       int cid = temp->getID(); //get client id
316//       packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
317//       assert(cd);
318    del->setPeerID(NETWORK_PEER_ID_BROADCAST);
319    if ( !del->send( static_cast<Host*>(this) ) )
320      orxout(internal_warning, context::network) << "Server: could not broadcast deleteObjects packet" << endl;
321//       temp=temp->next();
322      // gs gets automatically deleted by enet callback
323//     }
324//     delete del;
325    return true;
326  }
327
328
329  void Server::addPeer(uint32_t peerID)
330  {
331//     static unsigned int newid=1;
332//
333//     orxout(internal_info, context::network) << "Server: adding client" << endl;
334//     ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
335//     if(!temp)
336//     {
337//       orxout(internal_warning, context::network) << "Server: could not add client" << endl;
338//     }
339//     temp->setID(newid);
340//     temp->setPeer(event->peer);
341
342    // inform all the listeners
343    this->clientIDs_.push_back(peerID);
344    ClientConnectionListener::broadcastClientConnected(peerID);
345    GamestateManager::addPeer(peerID);
346
347//     ++newid;
348
349    orxout(internal_info, context::network) << "Server: added client id: " << peerID << endl;
350    createClient(peerID);
351}
352
353  void Server::removePeer(uint32_t peerID)
354  {
355    orxout(verbose, context::network) << "removing client from list" << endl;
356//     ClientInformation *client = ClientInformation::findClient(&event->peer->address);
357//     if(!client)
358//       return;
359//     else
360//     {
361  std::vector<uint32_t>::iterator it;
362  for( it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it )
363  {
364    if( *it == peerID )
365    {
366      this->clientIDs_.erase(it);
367      break;
368    }
369  }
370  ClientConnectionListener::broadcastClientDisconnected(peerID);
371  GamestateManager::removePeer(peerID);
372      //ServerConnection::disconnectClient( client );
373      //ClientConnectionListener::broadcastClientDisconnected( client->getID() ); //this is done in ClientInformation now
374//       delete client;
375//     }
376  }
377 
378  void Server::processPacket(packet::Packet* packet)
379  {
380    if( packet->isReliable() )
381    {
382      if( this->getLastReceivedGamestateID(packet->getPeerID()) >= packet->getRequiredGamestateID() )
383        packet->process(static_cast<Host*>(this));
384      else
385        this->packetQueue_.push_back(packet);
386    }
387    else
388      packet->process(static_cast<Host*>(this));
389  }
390
391
392  bool Server::createClient(int clientID)
393  {
394//     ClientInformation *temp = ClientInformation::findClient(clientID);
395//     if(!temp)
396//     {
397//       orxout(internal_error, context::network) << "Server. could not create client with id: " << clientID << endl;
398//       return false;
399//     }
400//     orxout(verbose, context::network) << "Con.Man: creating client id: " << temp->getID() << endl;
401
402    // synchronise class ids
403    syncClassid(clientID);
404
405    // now synchronise functionIDs
406    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
407    fIDs->setPeerID(clientID);
408    bool b = fIDs->send( static_cast<Host*>(this) );
409    assert(b);
410
411//     temp->setSynched(true);
412    GamestateManager::setSynched(clientID);
413   
414    orxout(verbose, context::network) << "sending welcome" << endl;
415    packet::Welcome *w = new packet::Welcome(clientID);
416    w->setPeerID(clientID);
417    b = w->send( static_cast<Host*>(this) );
418    assert(b);
419//     packet::Gamestate *g = new packet::Gamestate();
420//     g->setPeerID(clientID);
421//     b = g->collectData(0,packet::GAMESTATE_MODE_SERVER);
422//     assert(b);
423//     if(!b)
424//       return false; //no data for the client
425// //     b = g->compressData();
426// //     assert(b);
427//     b = g->send( static_cast<Host*>(this) );
428//     assert(b);
429    return true;
430  }
431
432  void Server::disconnectClient( uint32_t clientID )
433  {
434    ServerConnection::disconnectClient( clientID );
435    GamestateManager::removePeer( clientID );
436    // inform all the listeners
437    // ClientConnectionListener::broadcastClientDisconnected(client->getID()); // this is done in ClientInformation now
438  }
439
440  bool Server::chat(const std::string& message)
441  {
442      return this->sendChat(message, Host::getPlayerID());
443  }
444
445  bool Server::broadcast(const std::string& message)
446  {
447      return this->sendChat(message, NETWORK_PEER_ID_BROADCAST);
448  }
449
450  bool Server::sendChat(const std::string& message, unsigned int clientID)
451  {
452//     ClientInformation *temp = ClientInformation::getBegin();
453    packet::Chat *chat;
454//     while(temp)
455    {
456      chat = new packet::Chat(message, clientID);
457      chat->setPeerID(NETWORK_PEER_ID_BROADCAST);
458      chat->send( static_cast<Host*>(this) );
459//         orxout(internal_warning, context::network) << "could not send Chat message to client ID: " << temp->getID() << endl;
460//       temp = temp->next();
461    }
462//    orxout(message) << "Player " << Host::getPlayerID() << ": " << message << endl;
463    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
464      it->incomingChat(message, clientID);
465
466    return true;
467  }
468
469  void Server::syncClassid(unsigned int clientID)
470  {
471    int failures=0;
472    packet::ClassID *classid = new packet::ClassID();
473    classid->setPeerID(clientID);
474    while(!classid->send( static_cast<Host*>(this) ) && failures < 10){
475      failures++;
476    }
477    assert(failures<10);
478    orxout(verbose, context::network) << "syncClassid:\tall synchClassID packets have been sent" << endl;
479  }
480
481}
Note: See TracBrowser for help on using the repository browser.