Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/network/Server.cc @ 7978

Last change on this file since 7978 was 7801, checked in by dafrick, 14 years ago

Merging presentation2 branch back to trunk.

  • 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
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/Debug.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    COUT(4) << "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    COUT(4) << "closing server" << endl;
140    this->disconnectClients();
141    this->closeListener();
142
143    /* tell master server we're closing */
144    COUT(2) << "disconnecting." << endl;
145    WANDiscoverable::setActivity(false);   
146    COUT(2) << "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(temp->getID());
159      if(!chat->send( static_cast<Host*>(this) ))
160        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
161      temp = temp->next();
162    }
163//    COUT(1) << "Player " << playerID << ": " << message << std::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 ( ClientInformation::hasClients() )
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  }
242
243  void Server::printRTT()
244  {
245    for( ClientInformation* temp=ClientInformation::getBegin(); temp!=0; temp=temp->next() )
246      COUT(0) << "Round trip time to client with ID: " << temp->getID() << " is " << temp->getRTT() << " ms" << endl;
247  }
248
249  /**
250   * @brief: return packet loss ratio to client (scales from 0 to 1)
251   */
252  double Server::getPacketLoss(unsigned int clientID)
253  {
254    assert(ClientInformation::findClient(clientID));
255    return ClientInformation::findClient(clientID)->getPacketLoss();
256  }
257
258  /**
259  * takes a new snapshot of the gamestate and sends it to the clients
260  */
261  void Server::updateGamestate()
262  {
263    if( ClientInformation::getBegin()==NULL )
264      //no client connected
265      return;
266    GamestateManager::update();
267//     COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
268    //std::cout << "updated gamestate, sending it" << std::endl;
269    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
270    sendGameStates();
271    sendObjectDeletes();
272//     COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
273    //std::cout << "sent gamestate" << std::endl;
274  }
275
276  /**
277  * sends the current gamestate to all peers
278  */
279  bool Server::sendGameStates()
280  {
281    std::vector<packet::Gamestate*> gamestates = GamestateManager::getGamestates();
282    std::vector<packet::Gamestate*>::iterator it;
283    for( it = gamestates.begin(); it != gamestates.end(); ++it )
284    {
285      (*it)->send(static_cast<Host*>(this));
286    }
287    return true;
288  }
289
290
291  bool Server::sendObjectDeletes()
292  {
293    ClientInformation *temp = ClientInformation::getBegin();
294    if( temp == NULL )
295      //no client connected
296      return true;
297    packet::DeleteObjects *del = new packet::DeleteObjects();
298    if(!del->fetchIDs())
299    {
300      delete del;
301      return true;  //everything ok (no deletes this tick)
302    }
303//     COUT(3) << "sending DeleteObjects" << std::endl;
304    while(temp != NULL){
305      if( !(temp->getSynched()) )
306      {
307        COUT(5) << "Server: not sending gamestate" << std::endl;
308        temp=temp->next();
309        continue;
310      }
311      int cid = temp->getID(); //get client id
312      packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
313      assert(cd);
314      cd->setPeerID(cid);
315      if ( !cd->send( static_cast<Host*>(this) ) )
316        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended" << std::endl;
317      temp=temp->next();
318      // gs gets automatically deleted by enet callback
319    }
320    delete del;
321    return true;
322  }
323
324
325  void Server::addPeer(ENetEvent *event)
326  {
327    static unsigned int newid=1;
328
329    COUT(2) << "Server: adding client" << std::endl;
330    ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
331    if(!temp)
332    {
333      COUT(2) << "Server: could not add client" << std::endl;
334    }
335    temp->setID(newid);
336    temp->setPeer(event->peer);
337
338    // inform all the listeners
339    ClientConnectionListener::broadcastClientConnected(newid);
340    GamestateManager::addPeer(newid);
341
342    ++newid;
343
344    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
345    createClient(temp->getID());
346}
347
348  void Server::removePeer(ENetEvent *event)
349  {
350    COUT(4) << "removing client from list" << std::endl;
351    ClientInformation *client = ClientInformation::findClient(&event->peer->address);
352    if(!client)
353      return;
354    else
355    {
356      GamestateManager::removePeer(client->getID());
357      //ServerConnection::disconnectClient( client );
358      //ClientConnectionListener::broadcastClientDisconnected( client->getID() ); //this is done in ClientInformation now
359      delete client;
360    }
361  }
362 
363  void Server::processPacket(packet::Packet* packet)
364  {
365    if( packet->isReliable() )
366    {
367      if( this->getLastProcessedGamestateID(packet->getPeerID()) >= packet->getRequiredGamestateID() )
368        packet->process(static_cast<Host*>(this));
369      else
370        this->packetQueue_.push_back(packet);
371    }
372    else
373      packet->process(static_cast<Host*>(this));
374  }
375
376
377  bool Server::createClient(int clientID)
378  {
379    ClientInformation *temp = ClientInformation::findClient(clientID);
380    if(!temp)
381    {
382      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
383      return false;
384    }
385    COUT(4) << "Con.Man: creating client id: " << temp->getID() << std::endl;
386
387    // synchronise class ids
388    syncClassid(temp->getID());
389
390    // now synchronise functionIDs
391    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
392    fIDs->setPeerID(clientID);
393    bool b = fIDs->send( static_cast<Host*>(this) );
394    assert(b);
395
396    temp->setSynched(true);
397    GamestateManager::setSynched(clientID);
398   
399    COUT(4) << "sending welcome" << std::endl;
400    packet::Welcome *w = new packet::Welcome(temp->getID(), temp->getShipID());
401    w->setPeerID(temp->getID());
402    b = w->send( static_cast<Host*>(this) );
403    assert(b);
404    packet::Gamestate *g = new packet::Gamestate();
405    g->setPeerID(temp->getID());
406    b = g->collectData(0,packet::GAMESTATE_MODE_SERVER);
407    assert(b);
408    if(!b)
409      return false; //no data for the client
410//     b = g->compressData();
411//     assert(b);
412    b = g->send( static_cast<Host*>(this) );
413    assert(b);
414    return true;
415  }
416
417  void Server::disconnectClient( ClientInformation *client )
418  {
419    ServerConnection::disconnectClient( client );
420    GamestateManager::removePeer(client->getID());
421    // inform all the listeners
422    // ClientConnectionListener::broadcastClientDisconnected(client->getID()); // this is done in ClientInformation now
423  }
424
425  bool Server::chat(const std::string& message)
426  {
427      return this->sendChat(message, Host::getPlayerID());
428  }
429
430  bool Server::broadcast(const std::string& message)
431  {
432      return this->sendChat(message, CLIENTID_UNKNOWN);
433  }
434
435  bool Server::sendChat(const std::string& message, unsigned int clientID)
436  {
437    ClientInformation *temp = ClientInformation::getBegin();
438    packet::Chat *chat;
439    while(temp)
440    {
441      chat = new packet::Chat(message, clientID);
442      chat->setPeerID(temp->getID());
443      if(!chat->send( static_cast<Host*>(this) ))
444        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
445      temp = temp->next();
446    }
447//    COUT(1) << "Player " << Host::getPlayerID() << ": " << message << std::endl;
448    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
449      it->incomingChat(message, clientID);
450
451    return true;
452  }
453
454  void Server::syncClassid(unsigned int clientID)
455  {
456    int failures=0;
457    packet::ClassID *classid = new packet::ClassID();
458    classid->setPeerID(clientID);
459    while(!classid->send( static_cast<Host*>(this) ) && failures < 10){
460      failures++;
461    }
462    assert(failures<10);
463    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
464  }
465
466}
Note: See TracBrowser for help on using the repository browser.