Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network5/src/libraries/network/Server.cc @ 7777

Last change on this file since 7777 was 7777, checked in by scheusso, 14 years ago

some () structural changes
some functional changes (GamestateClient replaced through GamestateManager on client)
reliable packets get buffered until a recent gamestate arrived and got processed

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