Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core6/src/libraries/network/Server.cc @ 9649

Last change on this file since 9649 was 9557, checked in by landauf, 12 years ago

moved all files in core which are used for object management to a new subdirectory (core/object/)

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