Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/masterserver/src/libraries/network/Server.cc @ 7753

Last change on this file since 7753 was 7650, checked in by smerkli, 14 years ago

Minimum target achieved for today, servers can log on to master server, clients can get server list. To be debugged.

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