Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/kicklib2/src/libraries/network/Server.cc @ 8660

Last change on this file since 8660 was 8313, checked in by rgrieder, 14 years ago

Not using doubles at all in Orxonox because the Renderer (DirectX in particular) might set to single precision. So the general strategy would be not to use doubles at all.

  • 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  float 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.