Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9615 was 8858, checked in by landauf, 13 years ago

merged output branch back to trunk.

Changes:

  • you have to include util/Output.h instead of util/Debug.h
  • COUT(x) is now called orxout(level)
  • output levels are now defined by an enum instead of numbers. see util/Output.h for the definition
  • it's possible to use output contexts with orxout(level, context). see util/Output.h for some common contexts. you can define more contexts
  • you must use 'endl' at the end of an output message, '\n' does not flush the message

Output levels:

  • instead of COUT(0) use orxout()
  • instead of COUT(1) use orxout(user_error) or orxout(internal_error)
  • instead of COUT(2) use orxout(user_warning) or orxout(internal_warning)
  • instead of COUT(3) use orxout(user_status/user_info) or orxout(internal_status/internal_info)
  • instead of COUT(4) use orxout(verbose)
  • instead of COUT(5) use orxout(verbose_more)
  • instead of COUT(6) use orxout(verbose_ultra)

Guidelines:

  • user_* levels are for the user, visible in the console and the log-file
  • internal_* levels are for developers, visible in the log-file
  • verbose_* levels are for debugging, only visible if the context of the output is activated

Usage in C++:

  • orxout() << "message" << endl;
  • orxout(level) << "message" << endl;
  • orxout(level, context) << "message" << endl;

Usage in Lua:

  • orxout("message")
  • orxout(orxonox.level.levelname, "message")
  • orxout(orxonox.level.levelname, "context", "message")

Usage in Tcl (and in the in-game-console):

  • orxout levelname message
  • orxout_context levelname context message
  • shortcuts: log message, error message, warning message, status message, info message, debug message
  • Property svn:eol-style set to native
File size: 12.9 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"
[8858]49#include "util/Output.h"
[3214]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"
[8327]58// #include "ClientInformation.h"
[3084]59#include "FunctionCallManager.h"
[3214]60#include "GamestateManager.h"
[1502]61
[2171]62namespace orxonox
[1502]63{
[2087]64  const unsigned int MAX_FAILURES = 20;
[1747]65
[1502]66  /**
67  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
68  *
69  */
[7163]70  Server::Server()
71  {
[3304]72    this->timeSinceLastUpdate_=0;
[1502]73  }
[1747]74
[7163]75  Server::Server(int port)
76  {
[3214]77    this->setPort( port );
[3304]78    this->timeSinceLastUpdate_=0;
[1502]79  }
80
81  /**
82  * Constructor
83  * @param port Port to listen on
84  * @param bindAddress Address to listen on
85  */
[7163]86  Server::Server(int port, const std::string& bindAddress)
87  {
[3214]88    this->setPort( port );
89    this->setBindAddress( bindAddress );
[3304]90    this->timeSinceLastUpdate_=0;
[1502]91  }
92
93  /**
[1907]94  * @brief Destructor
95  */
[7163]96  Server::~Server()
97  {
[1907]98  }
[1502]99
100  /**
101  * This function opens the server by creating the listener thread
102  */
[7163]103  void Server::open()
104  {
105    Host::setActive(true);
[8858]106    orxout(verbose, context::network) << "opening server" << endl;
[3214]107    this->openListener();
[8858]108
[7801]109    /* make discoverable on LAN */
[7163]110    LANDiscoverable::setActivity(true);
[7801]111
112    /* make discoverable on WAN */
113    WANDiscoverable::setActivity(true);
114
115    /* done */
[1502]116    return;
117  }
118
119  /**
120  * This function closes the server
121  */
[7163]122  void Server::close()
123  {
124    Host::setActive(false);
[8858]125    orxout(verbose, context::network) << "closing server" << endl;
[3214]126    this->disconnectClients();
127    this->closeListener();
[7801]128
129    /* tell master server we're closing */
[8858]130    orxout(internal_info, context::network) << "disconnecting." << endl;
131    WANDiscoverable::setActivity(false);
132    orxout(internal_info, context::network) << "disconnecting done" << endl;
[7801]133
[7163]134    LANDiscoverable::setActivity(false);
[1502]135    return;
136  }
137
138  /**
139  * Run this function once every tick
140  * calls processQueue and updateGamestate
141  * @param time time since last tick
142  */
[7163]143  void Server::update(const Clock& time)
144  {
[3304]145    // receive incoming packets
[3214]146    Connection::processQueue();
[7801]147
[7163]148    // receive and process incoming discovery packets
149    LANDiscoverable::update();
[6417]150
[8327]151    if ( GamestateManager::hasPeers() )
[3214]152    {
[3304]153      // process incoming gamestates
154      GamestateManager::processGamestates();
[7801]155      FunctionCallManager::processBufferedFunctionCalls();
[6417]156
[3304]157      // send function calls to clients
[7801]158      FunctionCallManager::sendCalls( static_cast<Host*>(this) );
[6417]159
[3304]160      //this steers our network frequency
161      timeSinceLastUpdate_+=time.getDeltaTime();
162      if(timeSinceLastUpdate_>=NETWORK_PERIOD)
163      {
164        timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
165        updateGamestate();
166      }
[7801]167//       sendPackets(); // flush the enet queue
[1502]168    }
169  }
[1747]170
[7801]171  void Server::queuePacket(ENetPacket *packet, int clientID, uint8_t channelID)
[7163]172  {
[7801]173    ServerConnection::addPacket(packet, clientID, channelID);
[1735]174  }
[6417]175
[2087]176  /**
[6417]177   * @brief: returns ping time to client in milliseconds
[2087]178   */
[7163]179  unsigned int Server::getRTT(unsigned int clientID)
180  {
[8327]181//     assert(ClientInformation::findClient(clientID));
182//     return ClientInformation::findClient(clientID)->getRTT();
183    // TODO: reimplement
184    return 0;
[2087]185  }
[6417]186
[5961]187  void Server::printRTT()
188  {
[8327]189//     for( ClientInformation* temp=ClientInformation::getBegin(); temp!=0; temp=temp->next() )
[8858]190//       orxout(message) << "Round trip time to client with ID: " << temp->getID() << " is " << temp->getRTT() << " ms" << endl;
[5961]191  }
[1502]192
193  /**
[2087]194   * @brief: return packet loss ratio to client (scales from 0 to 1)
195   */
[8351]196  float Server::getPacketLoss(unsigned int clientID)
[7163]197  {
[8327]198//     assert(ClientInformation::findClient(clientID));
199//     return ClientInformation::findClient(clientID)->getPacketLoss();
200    return 0.;
[2087]201  }
[1502]202
203  /**
204  * takes a new snapshot of the gamestate and sends it to the clients
205  */
[7163]206  void Server::updateGamestate()
207  {
[8327]208    if( this->clientIDs_.size()==0 )
[2662]209      //no client connected
[3304]210      return;
211    GamestateManager::update();
[8858]212//     orxout(verbose_more, context::network) << "Server: one gamestate update complete, goig to sendGameState" << endl;
213    //orxout(verbose_more, context::network) << "updated gamestate, sending it" << endl;
[1502]214    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
[7801]215    sendGameStates();
[1907]216    sendObjectDeletes();
[8858]217//     orxout(verbose_more, context::network) << "Server: one sendGameState turn complete, repeat in next tick" << endl;
218    //orxout(verbose_more, context::network) << "sent gamestate" << endl;
[1502]219  }
220
221  /**
[7801]222  * sends the current gamestate to all peers
[1502]223  */
[7801]224  bool Server::sendGameStates()
[7163]225  {
[7801]226    std::vector<packet::Gamestate*> gamestates = GamestateManager::getGamestates();
227    std::vector<packet::Gamestate*>::iterator it;
228    for( it = gamestates.begin(); it != gamestates.end(); ++it )
229    {
230      (*it)->send(static_cast<Host*>(this));
231    }
[1502]232    return true;
233  }
[1747]234
[7801]235
[7163]236  bool Server::sendObjectDeletes()
237  {
[8327]238//     ClientInformation *temp = ClientInformation::getBegin();
239//     if( temp == NULL )
[2662]240      //no client connected
[8327]241    if( this->clientIDs_.size()==0 )
[2662]242      return true;
[1907]243    packet::DeleteObjects *del = new packet::DeleteObjects();
244    if(!del->fetchIDs())
[5929]245    {
246      delete del;
[1907]247      return true;  //everything ok (no deletes this tick)
[5929]248    }
[8858]249//     orxout(verbose, context::network) << "sending DeleteObjects" << endl;
[8327]250//     while(temp != NULL){
251//       if( !(temp->getSynched()) )
252//       {
[8858]253//         orxout(verbose_more, context::network) << "Server: not sending gamestate" << endl;
[8327]254//         temp=temp->next();
255//         continue;
256//       }
257//       int cid = temp->getID(); //get client id
258//       packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
259//       assert(cd);
260    del->setPeerID(NETWORK_PEER_ID_BROADCAST);
261    if ( !del->send( static_cast<Host*>(this) ) )
[8858]262      orxout(internal_warning, context::network) << "Server: could not broadcast deleteObjects packet" << endl;
[8327]263//       temp=temp->next();
[1907]264      // gs gets automatically deleted by enet callback
[8327]265//     }
266//     delete del;
[1907]267    return true;
268  }
[1747]269
[1907]270
[8327]271  void Server::addPeer(uint32_t peerID)
[7163]272  {
[8327]273//     static unsigned int newid=1;
[8858]274//
275//     orxout(internal_info, context::network) << "Server: adding client" << endl;
[8327]276//     ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
277//     if(!temp)
278//     {
[8858]279//       orxout(internal_warning, context::network) << "Server: could not add client" << endl;
[8327]280//     }
281//     temp->setID(newid);
282//     temp->setPeer(event->peer);
[2087]283
284    // inform all the listeners
[8327]285    this->clientIDs_.push_back(peerID);
286    ClientConnectionListener::broadcastClientConnected(peerID);
287    GamestateManager::addPeer(peerID);
[2087]288
[8327]289//     ++newid;
[2087]290
[8858]291    orxout(internal_info, context::network) << "Server: added client id: " << peerID << endl;
[8327]292    createClient(peerID);
[2087]293}
[1747]294
[8327]295  void Server::removePeer(uint32_t peerID)
[5929]296  {
[8858]297    orxout(verbose, context::network) << "removing client from list" << endl;
[8327]298//     ClientInformation *client = ClientInformation::findClient(&event->peer->address);
299//     if(!client)
300//       return;
301//     else
302//     {
303  std::vector<uint32_t>::iterator it;
304  for( it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it )
305  {
306    if( *it == peerID )
[5929]307    {
[8327]308      this->clientIDs_.erase(it);
309      break;
310    }
311  }
312  ClientConnectionListener::broadcastClientDisconnected(peerID);
313  GamestateManager::removePeer(peerID);
[5929]314      //ServerConnection::disconnectClient( client );
[5961]315      //ClientConnectionListener::broadcastClientDisconnected( client->getID() ); //this is done in ClientInformation now
[8327]316//       delete client;
317//     }
[5929]318  }
[8858]319
[7801]320  void Server::processPacket(packet::Packet* packet)
321  {
322    if( packet->isReliable() )
323    {
[8327]324      if( this->getLastReceivedGamestateID(packet->getPeerID()) >= packet->getRequiredGamestateID() )
[7801]325        packet->process(static_cast<Host*>(this));
326      else
327        this->packetQueue_.push_back(packet);
328    }
329    else
330      packet->process(static_cast<Host*>(this));
331  }
[5929]332
[7801]333
[7163]334  bool Server::createClient(int clientID)
335  {
[8327]336//     ClientInformation *temp = ClientInformation::findClient(clientID);
337//     if(!temp)
338//     {
[8858]339//       orxout(internal_error, context::network) << "Server. could not create client with id: " << clientID << endl;
[8327]340//       return false;
341//     }
[8858]342//     orxout(verbose, context::network) << "Con.Man: creating client id: " << temp->getID() << endl;
[6417]343
[3084]344    // synchronise class ids
[8327]345    syncClassid(clientID);
[6417]346
[3084]347    // now synchronise functionIDs
348    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
[7801]349    fIDs->setPeerID(clientID);
350    bool b = fIDs->send( static_cast<Host*>(this) );
[3084]351    assert(b);
[6417]352
[8327]353//     temp->setSynched(true);
[7801]354    GamestateManager::setSynched(clientID);
[8858]355
356    orxout(verbose, context::network) << "sending welcome" << endl;
[8706]357    packet::Welcome *w = new packet::Welcome(clientID);
[8327]358    w->setPeerID(clientID);
[7801]359    b = w->send( static_cast<Host*>(this) );
[1907]360    assert(b);
[8327]361//     packet::Gamestate *g = new packet::Gamestate();
362//     g->setPeerID(clientID);
363//     b = g->collectData(0,packet::GAMESTATE_MODE_SERVER);
[7801]364//     assert(b);
[8327]365//     if(!b)
366//       return false; //no data for the client
367// //     b = g->compressData();
368// //     assert(b);
369//     b = g->send( static_cast<Host*>(this) );
370//     assert(b);
[1502]371    return true;
372  }
[6417]373
[8327]374  void Server::disconnectClient( uint32_t clientID )
[7163]375  {
[8327]376    ServerConnection::disconnectClient( clientID );
377    GamestateManager::removePeer( clientID );
[5929]378    // inform all the listeners
[5961]379    // ClientConnectionListener::broadcastClientDisconnected(client->getID()); // this is done in ClientInformation now
[1502]380  }
[2087]381
[8858]382  /**
383   * @brief Sends a chat message to the given target ID.
384   * @param message message to be sent
385   * @param sourceID the ID of the sender
386   * @param targetID the ID of the receiver
387   */
388  void Server::doSendChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
[7163]389  {
[8858]390    // check if the target exists. just ignore the message otherwise
391    if (!this->isValidTarget(targetID)) // TODO: remove this if an invalid clientIDs don't trigger assertions anymore
392      return;
393
394    // send the message to the target
395    packet::Chat* packet = new packet::Chat(message, sourceID, targetID);
396    packet->setPeerID(targetID);
397    packet->send( static_cast<Host*>(this) );
398
399    // if the target is (or includes) this host as well, call the parent function which passes the message to the listeners
400    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == Host::getPlayerID())
401      Host::doReceiveChat(message, sourceID, targetID);
[2087]402  }
403
[8858]404  /**
405   * @brief Gets called if a packet::Chat packet is received. Forwards the packet to the target
406   * and calls the parent function if necessary.
407   */
408  void Server::doReceiveChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
[7163]409  {
[8858]410      this->doSendChat(message, sourceID, targetID);
[2087]411  }
412
[8858]413  /**
414   * @brief Returns true if the target ID is in the list of clients (or if it
415   * corresponds to the broadcast or the server ID).
416   */
417  bool Server::isValidTarget(unsigned int targetID)
[7163]418  {
[8858]419    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == NETWORK_PEER_ID_SERVER)
420      return true;
[2087]421
[8858]422    std::vector<uint32_t>::iterator it;
423    for( it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it )
424      if( *it == targetID )
425        return true;
426
427    return false;
[1907]428  }
[1747]429
[7163]430  void Server::syncClassid(unsigned int clientID)
431  {
[3214]432    int failures=0;
433    packet::ClassID *classid = new packet::ClassID();
[7801]434    classid->setPeerID(clientID);
435    while(!classid->send( static_cast<Host*>(this) ) && failures < 10){
[3214]436      failures++;
437    }
438    assert(failures<10);
[8858]439    orxout(verbose, context::network) << "syncClassid:\tall synchClassID packets have been sent" << endl;
[3214]440  }
441
[1502]442}
Note: See TracBrowser for help on using the repository browser.