Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8016 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
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
63namespace orxonox
64{
65  const unsigned int MAX_FAILURES = 20;
66
67  /**
68  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
69  *
70  */
71  Server::Server()
72  {
73    this->timeSinceLastUpdate_=0;
74  }
75
76  Server::Server(int port)
77  {
78    this->setPort( port );
79    this->timeSinceLastUpdate_=0;
80  }
81
82  /**
83  * Constructor
84  * @param port Port to listen on
85  * @param bindAddress Address to listen on
86  */
87  Server::Server(int port, const std::string& bindAddress)
88  {
89    this->setPort( port );
90    this->setBindAddress( bindAddress );
91    this->timeSinceLastUpdate_=0;
92  }
93
94  /**
95  * @brief Destructor
96  */
97  Server::~Server()
98  {
99  }
100
101
102  /* TODO */
103  void Server::helper_ConnectToMasterserver()
104  {
105    /* initialize it and see if it worked */
106    if( msc.initialize() )
107    { COUT(1) << "Error: could not initialize master server communications!\n";
108      return;
109    }
110
111    /* connect and see if it worked */
112    if( msc.connect( MS_ADDRESS, 1234 ) )
113    { COUT(1) << "Error: could not connect to master server!\n";
114      return;
115    }
116
117    /* now send the master server some note we're here */
118    msc.sendRequest( MSPROTO_GAME_SERVER " " MSPROTO_REGISTER_SERVER );
119  }
120
121  /**
122  * This function opens the server by creating the listener thread
123  */
124  void Server::open()
125  {
126    Host::setActive(true);
127    COUT(4) << "opening server" << endl;
128    this->openListener();
129   
130    /* make discoverable on LAN */
131    LANDiscoverable::setActivity(true);
132
133    /* make discoverable on WAN */
134    helper_ConnectToMasterserver();
135
136    /* done */
137    return;
138  }
139
140  /**
141  * This function closes the server
142  */
143  void Server::close()
144  {
145    Host::setActive(false);
146    COUT(4) << "closing server" << endl;
147    this->disconnectClients();
148    this->closeListener();
149    LANDiscoverable::setActivity(false);
150    return;
151  }
152
153  bool Server::processChat(const std::string& message, unsigned int playerID)
154  {
155    ClientInformation *temp = ClientInformation::getBegin();
156    packet::Chat *chat;
157    while(temp){
158      chat = new packet::Chat(message, playerID);
159      chat->setClientID(temp->getID());
160      if(!chat->send())
161        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
162      temp = temp->next();
163    }
164//    COUT(1) << "Player " << playerID << ": " << message << std::endl;
165    return true;
166  }
167
168
169  /* TODO */
170  int rephandler( char *addr, ENetEvent *ev )
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  { 
180    this->msc.pollForReply( rephandler ); 
181  }
182
183  /**
184  * Run this function once every tick
185  * calls processQueue and updateGamestate
186  * @param time time since last tick
187  */
188  void Server::update(const Clock& time)
189  {
190    // receive incoming packets
191    Connection::processQueue();
192
193    // receive and process incoming discovery packets
194    LANDiscoverable::update();
195
196    // receive and process requests from master server
197    helper_HandleMasterServerRequests();
198
199    if ( ClientInformation::hasClients() )
200    {
201      // process incoming gamestates
202      GamestateManager::processGamestates();
203
204      // send function calls to clients
205      FunctionCallManager::sendCalls();
206
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
215    }
216  }
217
218  bool Server::queuePacket(ENetPacket *packet, int clientID)
219  {
220    return ServerConnection::addPacket(packet, clientID);
221  }
222
223  /**
224   * @brief: returns ping time to client in milliseconds
225   */
226  unsigned int Server::getRTT(unsigned int clientID)
227  {
228    assert(ClientInformation::findClient(clientID));
229    return ClientInformation::findClient(clientID)->getRTT();
230  }
231
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  }
237
238  /**
239   * @brief: return packet loss ratio to client (scales from 0 to 1)
240   */
241  double Server::getPacketLoss(unsigned int clientID)
242  {
243    assert(ClientInformation::findClient(clientID));
244    return ClientInformation::findClient(clientID)->getPacketLoss();
245  }
246
247  /**
248  * takes a new snapshot of the gamestate and sends it to the clients
249  */
250  void Server::updateGamestate()
251  {
252    if( ClientInformation::getBegin()==NULL )
253      //no client connected
254      return;
255    GamestateManager::update();
256    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
257    //std::cout << "updated gamestate, sending it" << std::endl;
258    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
259    sendGameState();
260    sendObjectDeletes();
261    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
262    //std::cout << "sent gamestate" << std::endl;
263  }
264
265  bool Server::processPacket( ENetPacket *packet, ENetPeer *peer ){
266    packet::Packet *p = packet::Packet::createPacket(packet, peer);
267    return p->process();
268  }
269
270  /**
271  * sends the gamestate
272  */
273  bool Server::sendGameState()
274  {
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();
307    return true;
308  }
309
310  bool Server::sendObjectDeletes()
311  {
312    ClientInformation *temp = ClientInformation::getBegin();
313    if( temp == NULL )
314      //no client connected
315      return true;
316    packet::DeleteObjects *del = new packet::DeleteObjects();
317    if(!del->fetchIDs())
318    {
319      delete del;
320      return true;  //everything ok (no deletes this tick)
321    }
322//     COUT(3) << "sending DeleteObjects" << std::endl;
323    while(temp != NULL){
324      if( !(temp->getSynched()) )
325      {
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    }
339    delete del;
340    return true;
341  }
342
343
344  void Server::addPeer(ENetEvent *event)
345  {
346    static unsigned int newid=1;
347
348    COUT(2) << "Server: adding client" << std::endl;
349    ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
350    if(!temp)
351    {
352      COUT(2) << "Server: could not add client" << std::endl;
353    }
354    temp->setID(newid);
355    temp->setPeer(event->peer);
356
357    // inform all the listeners
358    ClientConnectionListener::broadcastClientConnected(newid);
359
360    ++newid;
361
362    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
363    createClient(temp->getID());
364}
365
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 );
375      //ClientConnectionListener::broadcastClientDisconnected( client->getID() ); //this is done in ClientInformation now
376      delete client;
377    }
378  }
379
380  bool Server::createClient(int clientID)
381  {
382    ClientInformation *temp = ClientInformation::findClient(clientID);
383    if(!temp)
384    {
385      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
386      return false;
387    }
388    COUT(5) << "Con.Man: creating client id: " << temp->getID() << std::endl;
389
390    // synchronise class ids
391    syncClassid(temp->getID());
392
393    // now synchronise functionIDs
394    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
395    fIDs->setClientID(clientID);
396    bool b = fIDs->send();
397    assert(b);
398
399    temp->setSynched(true);
400    COUT(4) << "sending welcome" << std::endl;
401    packet::Welcome *w = new packet::Welcome(temp->getID(), temp->getShipID());
402    w->setClientID(temp->getID());
403    b = w->send();
404    assert(b);
405    packet::Gamestate *g = new packet::Gamestate();
406    g->setClientID(temp->getID());
407    b = g->collectData(0,0x1);
408    if(!b)
409      return false; //no data for the client
410    b = g->compressData();
411    assert(b);
412    b = g->send();
413    assert(b);
414    return true;
415  }
416
417  void Server::disconnectClient( ClientInformation *client )
418  {
419    ServerConnection::disconnectClient( client );
420    GamestateManager::removeClient(client);
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->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    }
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->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
466}
Note: See TracBrowser for help on using the repository browser.