Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/network/Server.cc @ 2848

Last change on this file since 2848 was 2800, checked in by rgrieder, 15 years ago

Renaming "tick" to "update" for all those classes not inheriting from Tickable to avoid confusions.
GameState::ticked still exists, but that's going to change anyway.

  • Property svn:eol-style set to native
File size: 12.6 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, (C) 2007
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#include <enet/enet.h>
44#include <iostream>
45#include <cassert>
46
47
48#include "ConnectionManager.h"
49#include "ClientConnectionListener.h"
50#include "GamestateManager.h"
51#include "ClientInformation.h"
52#include "util/Sleep.h"
53#include "core/Clock.h"
54#include "core/ConsoleCommand.h"
55#include "core/CoreIncludes.h"
56#include "core/Iterator.h"
57#include "packet/Chat.h"
58#include "packet/Packet.h"
59#include "packet/Welcome.h"
60#include "packet/DeleteObjects.h"
61#include "util/Convert.h"
62#include "ChatListener.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    timeSinceLastUpdate_=0;
74    connection = new ConnectionManager();
75    gamestates_ = new GamestateManager();
76  }
77
78  Server::Server(int port){
79    timeSinceLastUpdate_=0;
80    connection = new ConnectionManager(port);
81    gamestates_ = new GamestateManager();
82  }
83
84  /**
85  * Constructor
86  * @param port Port to listen on
87  * @param bindAddress Address to listen on
88  */
89  Server::Server(int port, const std::string& bindAddress) {
90    timeSinceLastUpdate_=0;
91    connection = new ConnectionManager(port, bindAddress);
92    gamestates_ = new GamestateManager();
93  }
94
95  /**
96  * Constructor
97  * @param port Port to listen on
98  * @param bindAddress Address to listen on
99  */
100  Server::Server(int port, const char *bindAddress) {
101    timeSinceLastUpdate_=0;
102    connection = new ConnectionManager(port, bindAddress);
103    gamestates_ = new GamestateManager();
104  }
105
106  /**
107  * @brief Destructor
108  */
109  Server::~Server(){
110    if(connection)
111      delete connection;
112    if(gamestates_)
113      delete gamestates_;
114  }
115
116  /**
117  * This function opens the server by creating the listener thread
118  */
119  void Server::open() {
120    connection->createListener();
121    return;
122  }
123
124  /**
125  * This function closes the server
126  */
127  void Server::close() {
128    connection->quitListener();
129    return;
130  }
131
132  bool Server::processChat(const std::string& message, unsigned int playerID){
133    ClientInformation *temp = ClientInformation::getBegin();
134    packet::Chat *chat;
135    while(temp){
136      chat = new packet::Chat(message, playerID);
137      chat->setClientID(temp->getID());
138      if(!chat->send())
139        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
140      temp = temp->next();
141    }
142//    COUT(1) << "Player " << playerID << ": " << message << std::endl;
143    return true;
144  }
145
146
147  /**
148  * Run this function once every tick
149  * calls processQueue and updateGamestate
150  * @param time time since last tick
151  */
152  void Server::update(const Clock& time) {
153    processQueue();
154    //this steers our network frequency
155    timeSinceLastUpdate_+=time.getDeltaTime();
156    if(timeSinceLastUpdate_>=NETWORK_PERIOD){
157      timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
158      gamestates_->processGamestates();
159      updateGamestate();
160    }
161  }
162
163  bool Server::queuePacket(ENetPacket *packet, int clientID){
164    return connection->addPacket(packet, clientID);
165  }
166 
167  /**
168   * @brief: returns ping time to client in milliseconds
169   */
170  unsigned int Server::getPing(unsigned int clientID){
171    assert(ClientInformation::findClient(clientID));
172    return ClientInformation::findClient(clientID)->getRTT();
173  }
174
175  /**
176   * @brief: return packet loss ratio to client (scales from 0 to 1)
177   */
178  double Server::getPacketLoss(unsigned int clientID){
179    assert(ClientInformation::findClient(clientID));
180    return ClientInformation::findClient(clientID)->getPacketLoss();
181  }
182 
183  /**
184  * processes all the packets waiting in the queue
185  */
186  void Server::processQueue() {
187    ENetEvent *event;
188    while(!connection->queueEmpty()){
189      //std::cout << "Client " << clientID << " sent: " << std::endl;
190      //clientID here is a reference to grab clientID from ClientInformation
191      event = connection->getEvent();
192      if(!event)
193        continue;
194      assert(event->type != ENET_EVENT_TYPE_NONE);
195      switch( event->type ) {
196      case ENET_EVENT_TYPE_CONNECT:
197        COUT(3) << "processing event_Type_connect" << std::endl;
198        addClient(event);
199        break;
200      case ENET_EVENT_TYPE_DISCONNECT:
201        if(ClientInformation::findClient(&event->peer->address))
202          disconnectClient(event);
203        break;
204      case ENET_EVENT_TYPE_RECEIVE:
205        if(!processPacket(event->packet, event->peer))
206          COUT(3) << "processing incoming packet failed" << std::endl;
207        break;
208      default:
209        break;
210      }
211      delete event;
212      //if statement to catch case that packetbuffer is empty
213    }
214  }
215
216  /**
217  * takes a new snapshot of the gamestate and sends it to the clients
218  */
219  void Server::updateGamestate() {
220//     if( ClientInformation::getBegin()==NULL )
221      //no client connected
222//       return;
223    gamestates_->update();
224    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
225    //std::cout << "updated gamestate, sending it" << std::endl;
226    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
227    sendGameState();
228    sendObjectDeletes();
229    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
230    //std::cout << "sent gamestate" << std::endl;
231  }
232
233  bool Server::processPacket( ENetPacket *packet, ENetPeer *peer ){
234    packet::Packet *p = packet::Packet::createPacket(packet, peer);
235    return p->process();
236  }
237
238  /**
239  * sends the gamestate
240  */
241  bool Server::sendGameState() {
242    COUT(5) << "Server: starting function sendGameState" << std::endl;
243    ClientInformation *temp = ClientInformation::getBegin();
244    bool added=false;
245    while(temp != NULL){
246      if( !(temp->getSynched()) ){
247        COUT(5) << "Server: not sending gamestate" << std::endl;
248        temp=temp->next();
249        if(!temp)
250          break;
251        //think this works without continue
252        continue;
253      }
254      COUT(4) << "client id: " << temp->getID() << " RTT: " << temp->getRTT() << " loss: " << temp->getPacketLoss() << std::endl;
255      COUT(5) << "Server: doing gamestate gamestate preparation" << std::endl;
256      int gid = temp->getGamestateID(); //get gamestate id
257      int cid = temp->getID(); //get client id
258      COUT(5) << "Server: got acked (gamestate) ID from clientlist: " << gid << std::endl;
259      packet::Gamestate *gs = gamestates_->popGameState(cid);
260      if(gs==NULL){
261        COUT(2) << "Server: could not generate gamestate (NULL from compress)" << std::endl;
262        temp = temp->next();
263        continue;
264      }
265      //std::cout << "adding gamestate" << std::endl;
266      gs->setClientID(cid);
267      if ( !gs->send() ){
268        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
269        temp->addFailure();
270      }else
271        temp->resetFailures();
272      added=true;
273      temp=temp->next();
274      // gs gets automatically deleted by enet callback
275    }
276    return true;
277  }
278
279  bool Server::sendObjectDeletes(){
280    ClientInformation *temp = ClientInformation::getBegin();
281    if( temp == NULL )
282      //no client connected
283      return true;
284    packet::DeleteObjects *del = new packet::DeleteObjects();
285    if(!del->fetchIDs())
286      return true;  //everything ok (no deletes this tick)
287//     COUT(3) << "sending DeleteObjects" << std::endl;
288    while(temp != NULL){
289      if( !(temp->getSynched()) ){
290        COUT(5) << "Server: not sending gamestate" << std::endl;
291        temp=temp->next();
292        continue;
293      }
294      int cid = temp->getID(); //get client id
295      packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
296      assert(cd);
297      cd->setClientID(cid);
298      if ( !cd->send() )
299        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
300      temp=temp->next();
301      // gs gets automatically deleted by enet callback
302    }
303    return true;
304  }
305
306
307  bool Server::addClient(ENetEvent *event){
308    static unsigned int newid=1;
309
310    COUT(2) << "Server: adding client" << std::endl;
311    ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
312    if(!temp){
313      COUT(2) << "Server: could not add client" << std::endl;
314      return false;
315    }
316    /*if(temp==ClientInformation::getBegin()) { //not good if you use anything else than insertBack
317      newid=1;
318    }
319    else
320      newid=temp->prev()->getID()+1;*/
321    temp->setID(newid);
322    temp->setPeer(event->peer);
323
324    // inform all the listeners
325    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
326    while(listener){
327      listener->clientConnected(newid);
328      listener++;
329    }
330
331    newid++;
332
333    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
334    return createClient(temp->getID());
335}
336
337  bool Server::createClient(int clientID){
338    ClientInformation *temp = ClientInformation::findClient(clientID);
339    if(!temp){
340      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
341      return false;
342    }
343    COUT(4) << "Con.Man: creating client id: " << temp->getID() << std::endl;
344    connection->syncClassid(temp->getID());
345    temp->setSynched(true);
346    COUT(3) << "sending welcome" << std::endl;
347    packet::Welcome *w = new packet::Welcome(temp->getID(), temp->getShipID());
348    w->setClientID(temp->getID());
349    bool b = w->send();
350    assert(b);
351    packet::Gamestate *g = new packet::Gamestate();
352    g->setClientID(temp->getID());
353    b = g->collectData(0);
354    if(!b)
355      return false; //no data for the client
356    b = g->compressData();
357    assert(b);
358    b = g->send();
359    assert(b);
360    return true;
361  }
362
363  bool Server::disconnectClient(ENetEvent *event){
364    COUT(4) << "removing client from list" << std::endl;
365    //return removeClient(head_->findClient(&(peer->address))->getID());
366
367    //boost::recursive_mutex::scoped_lock lock(head_->mutex_);
368    ClientInformation *client = ClientInformation::findClient(&event->peer->address);
369    if(!client)
370      return false;
371    gamestates_->removeClient(client);
372
373// inform all the listeners
374    ObjectList<ClientConnectionListener>::iterator listener = ObjectList<ClientConnectionListener>::begin();
375    while(listener){
376      listener->clientDisconnected(client->getID());
377      listener++;
378    }
379
380    return ClientInformation::removeClient(event->peer);
381  }
382
383  void Server::disconnectClient(int clientID){
384    ClientInformation *client = ClientInformation::findClient(clientID);
385    if(client)
386      disconnectClient(client);
387  }
388  void Server::disconnectClient( ClientInformation *client){
389    connection->disconnectClient(client);
390    gamestates_->removeClient(client);
391  }
392
393  bool Server::chat(const std::string& message){
394      return this->sendChat(message, Host::getPlayerID());
395  }
396
397  bool Server::broadcast(const std::string& message){
398      return this->sendChat(message, CLIENTID_UNKNOWN);
399  }
400
401  bool Server::sendChat(const std::string& message, unsigned int clientID){
402    ClientInformation *temp = ClientInformation::getBegin();
403    packet::Chat *chat;
404    while(temp){
405      chat = new packet::Chat(message, clientID);
406      chat->setClientID(temp->getID());
407      if(!chat->send())
408        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
409      temp = temp->next();
410    }
411//    COUT(1) << "Player " << Host::getPlayerID() << ": " << message << std::endl;
412    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
413      it->incomingChat(message, clientID);
414
415    return true;
416  }
417
418}
Note: See TracBrowser for help on using the repository browser.