Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/network/Server.cc @ 1549

Last change on this file since 1549 was 1548, checked in by scheusso, 17 years ago

fixed that compiler error (missing ClassManager.h; improved network frequency handling

  • Property svn:eol-style set to native
File size: 13.2 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 <iostream>
44
45
46#include "ConnectionManager.h"
47#include "PacketTypes.h"
48#include "GameStateManager.h"
49#include "ClientInformation.h"
50//#include "NetworkFrameListener.h"
51#include "util/Sleep.h"
52#include "objects/SpaceShip.h"
53#include "core/ConsoleCommand.h"
54
55namespace network
56{
57  #define MAX_FAILURES 20;
58  #define NETWORK_FREQUENCY 30
59 
60  Server *Server::instance_=0;
61 
62  Server *Server::createSingleton(){
63    if(!instance_)
64      instance_ = new Server();
65    return instance_;
66  }
67  Server *Server::createSingleton(int port){
68    if(!instance_)
69      instance_ = new Server(port);
70    return instance_;
71  }
72  Server *Server::createSingleton(int port, std::string bindAddress){
73    if(!instance_)
74      instance_ = new Server(port, bindAddress);
75    return instance_;
76  }
77  Server *Server::createSingleton(int port, const char *bindAddress){
78    if(!instance_)
79      instance_ = new Server(port, bindAddress);
80    return instance_;
81  }
82 
83  Server *Server::getSingleton(){
84    return instance_;
85  }
86 
87 
88  /**
89  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
90  *
91  */
92  Server::Server() {
93    timeSinceLastUpdate_=0;
94    packet_gen = PacketGenerator();
95    clients = new ClientInformation(true);
96    connection = new ConnectionManager(clients);
97    gamestates = new GameStateManager(clients);
98  }
99 
100  Server::Server(int port){
101    timeSinceLastUpdate_=0;
102    packet_gen = PacketGenerator();
103    clients = new ClientInformation(true);
104    connection = new ConnectionManager(clients, port);
105    gamestates = new GameStateManager(clients);
106  }
107
108  /**
109  * Constructor
110  * @param port Port to listen on
111  * @param bindAddress Address to listen on
112  */
113  Server::Server(int port, std::string bindAddress) {
114    timeSinceLastUpdate_=0;
115    packet_gen = PacketGenerator();
116    clients = new ClientInformation();
117    connection = new ConnectionManager(port, bindAddress, clients);
118    gamestates = new GameStateManager(clients);
119  }
120
121  /**
122  * Constructor
123  * @param port Port to listen on
124  * @param bindAddress Address to listen on
125  */
126  Server::Server(int port, const char *bindAddress) {
127    timeSinceLastUpdate_=0;
128    packet_gen = PacketGenerator();
129    clients = new ClientInformation();
130    connection = new ConnectionManager(port, bindAddress, clients);
131    gamestates = new GameStateManager(clients);
132  }
133
134  /**
135  * This function opens the server by creating the listener thread
136  */
137  void Server::open() {
138    connection->createListener();
139    return;
140  }
141
142  /**
143  * This function closes the server
144  */
145  void Server::close() {
146    connection->quitListener();
147    return;
148  }
149
150  /**
151  * This function sends out a message to all clients
152  * @param msg message
153  * @return true/false
154  */
155  bool Server::sendChat(std::string msg) {
156    return sendChat(msg.c_str());
157  }
158
159  /**
160  * This function sends out a message to all clients
161  * @param msg message
162  * @return true/false
163  */
164  bool Server::sendChat(const char *msg) {
165    char *message = new char [strlen(msg)+10+1];
166    sprintf(message, "Player %d: %s", CLIENTID_SERVER, msg);
167    COUT(1) << message << std::endl;
168    ENetPacket *packet = packet_gen.chatMessage(message);
169    COUT(5) <<"Server: adding Packets" << std::endl;
170    return connection->addPacketAll(packet);
171  }
172
173  /**
174  * Run this function once every tick
175  * calls processQueue and updateGamestate
176  * @param time time since last tick
177  */
178  void Server::tick(float time) {
179    processQueue();
180    //this steers our network frequency
181    timeSinceLastUpdate_+=time;
182    if(timeSinceLastUpdate_>=(1./NETWORK_FREQUENCY)){
183      timeSinceLastUpdate_=(float)((int)(timeSinceLastUpdate_*NETWORK_FREQUENCY))/timeSinceLastUpdate_;
184//      timeSinceLastUpdate_-=1./NETWORK_FREQUENCY;
185      gamestates->processGameStates();
186      updateGamestate();
187    }
188    /*while(timeSinceLastUpdate_>1./NETWORK_FREQUENCY)
189      timeSinceLastUpdate_-=1./NETWORK_FREQUENCY;*/
190//     usleep(5000); // TODO remove
191    return;
192  }
193
194  /**
195  * processes all the packets waiting in the queue
196  */
197  void Server::processQueue() {
198    ENetEvent *event;
199    int clientID=-1;
200    while(!connection->queueEmpty()){
201      //std::cout << "Client " << clientID << " sent: " << std::endl;
202      //clientID here is a reference to grab clientID from ClientInformation
203      event = connection->getEvent();
204      if(!event)
205        continue;
206      assert(event->type != ENET_EVENT_TYPE_NONE);
207      switch( event->type ) {
208      case ENET_EVENT_TYPE_CONNECT:
209        COUT(3) << "processing event_Type_connect" << std::endl;
210        addClient(event);
211        break;
212      case ENET_EVENT_TYPE_DISCONNECT:
213        if(clients->findClient(&event->peer->address))
214          disconnectClient(event);
215        break;
216      case ENET_EVENT_TYPE_RECEIVE:
217        if(clients->findClient(&event->peer->address)){
218          clientID = clients->findClient(&event->peer->address)->getID();
219          if( !elaborate(event->packet, clientID) ) 
220            COUT(3) << "Server: could not elaborate" << std::endl;
221        }
222        break;
223      }
224      delete event;
225      //if statement to catch case that packetbuffer is empty
226    }
227  }
228
229  /**
230  * takes a new snapshot of the gamestate and sends it to the clients
231  */
232  void Server::updateGamestate() {
233    gamestates->update();
234    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
235    //std::cout << "updated gamestate, sending it" << std::endl;
236    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
237    sendGameState();
238    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
239    //std::cout << "sent gamestate" << std::endl;
240  }
241
242  /**
243  * sends the gamestate
244  */
245  bool Server::sendGameState() {
246    COUT(5) << "Server: starting function sendGameState" << std::endl;
247    ClientInformation *temp = clients;
248    bool added=false;
249    while(temp != NULL){
250      if(temp->getHead()){
251        temp=temp->next();
252        //think this works without continue
253        continue;
254      }
255      if( !(temp->getSynched()) ){
256        COUT(5) << "Server: not sending gamestate" << std::endl;
257        temp=temp->next();
258        //think this works without continue
259        continue;
260      }
261      COUT(4) << "client id: " << temp->getID() << " RTT: " << temp->getRTT() << " loss: " << temp->getPacketLoss() << std::endl;
262      COUT(5) << "Server: doing gamestate gamestate preparation" << std::endl;
263      int gid = temp->getGamestateID(); //get gamestate id
264      int cid = temp->getID(); //get client id
265      COUT(5) << "Server: got acked (gamestate) ID from clientlist: " << gid << std::endl;
266      GameStateCompressed *gs = gamestates->popGameState(cid);
267      if(gs==NULL){
268        COUT(2) << "Server: could not generate gamestate (NULL from compress)" << std::endl;
269        continue;
270      }
271      //std::cout << "adding gamestate" << std::endl;
272      ENetPacket *packet = packet_gen.gstate(gs);
273      if(!packet)
274        continue;
275      if ( !(connection->addPacket(packet, cid)) ){
276        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl; 
277        temp->addFailure();
278        /*if(temp->getFailures() > 0 )
279          disconnectClient(temp);*/
280      //std::cout << "added gamestate" << std::endl;
281      }else
282        temp->resetFailures();
283      added=true;
284      temp=temp->next();
285      // now delete gamestate
286      delete[] gs->data;
287      delete gs;
288    }
289    /*if(added) {
290      //std::cout << "send gamestates from server.cc in sendGameState" << std::endl;
291      return connection->sendPackets();
292    }*/
293    //COUT(5) << "Server: had no gamestates to send" << std::endl;
294    return true;
295  }
296
297  void Server::processAck( ack *data, int clientID) {
298    COUT(4) << "Server: processing ack from client: " << clientID << "; ack-id: " << data->a << std::endl;
299    gamestates->ackGameState(clientID, data->a);
300    delete data;
301  }
302 
303  bool Server::processConnectRequest( connectRequest *con, int clientID ){
304    //(COUT(3) << "processing connectRequest " << std::endl;
305    //connection->addPacket(packet_gen.gstate(gamestates->popGameState(clientID)) , clientID);
306    //createClient(clientID);
307    delete con;
308    return true;
309  }
310 
311  void Server::processGamestate( GameStateCompressed *data, int clientID){
312    COUT(4) << "processing partial gamestate from client " << clientID << std::endl;
313    gamestates->addGameState(data, clientID);
314        /*COUT(3) << "Could not push gamestate\t\t\t\t=====" << std::endl;
315    else
316      if(clients->findClient(clientID))
317        clients->findClient(clientID)->resetFailures();*/
318  }
319 
320  void Server::processChat( chat *data, int clientId){
321    char *message = new char [strlen(data->message)+10+1];
322    sprintf(message, "Player %d: %s", clientId, data->message);
323    COUT(1) << message << std::endl;
324    ENetPacket *pck = packet_gen.chatMessage(message);
325    connection->addPacketAll(pck);
326    delete[] data->message;
327    delete data;
328  }
329 
330  bool Server::addClient(ENetEvent *event){
331    ClientInformation *temp = clients->insertBack(new ClientInformation);
332    if(!temp){
333      COUT(2) << "Server: could not add client" << std::endl;
334      return false;
335    }
336    if(temp->prev()->getHead()) { //not good if you use anything else than insertBack
337      temp->prev()->setID(0); //bugfix: not necessary but usefull
338      temp->setID(1);
339    }
340    else
341      temp->setID(temp->prev()->getID()+1);
342    temp->setPeer(event->peer);
343    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
344    return createClient(temp->getID());
345  }
346 
347  bool Server::createClient(int clientID){
348    ClientInformation *temp = clients->findClient(clientID);
349    if(!temp){
350      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
351      return false;
352    }
353    COUT(4) << "Con.Man: creating client id: " << temp->getID() << std::endl;
354    connection->syncClassid(temp->getID());
355    COUT(5) << "creating spaceship for clientid: " << temp->getID() << std::endl;
356    // TODO: this is only a hack, untill we have a possibility to define default player-join actions
357    if(!createShip(temp))
358      COUT(2) << "Con.Man. could not create ship for clientid: " << clientID << std::endl;
359    else
360      COUT(3) << "created spaceship" << std::endl;
361    temp->setSynched(true);
362    COUT(3) << "sending welcome" << std::endl;
363    connection->sendWelcome(temp->getID(), temp->getShipID(), true);
364    return true;
365  }
366 
367  bool Server::createShip(ClientInformation *client){
368    if(!client)
369      return false;
370    orxonox::Identifier* id = ID("SpaceShip");
371    if(!id){
372      COUT(4) << "We could not create the SpaceShip for client: " << client->getID() << std::endl;
373      return false;
374    }
375    orxonox::SpaceShip *no = dynamic_cast<orxonox::SpaceShip *>(id->fabricate());
376    no->setPosition(orxonox::Vector3(0,0,80));
377    no->setScale(10);
378    //no->setYawPitchRoll(orxonox::Degree(-90),orxonox::Degree(-90),orxonox::Degree(0));
379    no->setMesh("assff.mesh");
380    no->setMaxSpeed(500);
381    no->setMaxSideAndBackSpeed(50);
382    no->setMaxRotation(1.0);
383    no->setTransAcc(200);
384    no->setRotAcc(3.0);
385    no->setTransDamp(75);
386    no->setRotDamp(1.0);
387    no->setCamera("cam_"+client->getID());
388    no->classID = id->getNetworkID();
389    no->create();
390   
391    client->setShipID(no->objectID);
392    return true;
393  }
394 
395  bool Server::disconnectClient(ENetEvent *event){
396    COUT(4) << "removing client from list" << std::endl;
397    //return removeClient(head_->findClient(&(peer->address))->getID());
398   
399    //boost::recursive_mutex::scoped_lock lock(head_->mutex_);
400    orxonox::Iterator<orxonox::SpaceShip> it = orxonox::ObjectList<orxonox::SpaceShip>::start();
401    ClientInformation *client = clients->findClient(&event->peer->address);
402    if(!client)
403      return false;
404    while(it){
405      if(it->objectID!=client->getShipID()){
406        ++it;
407        continue;
408      }
409      orxonox::Iterator<orxonox::SpaceShip> temp=it;
410      ++it;
411      delete  *temp;
412      return clients->removeClient(event->peer);
413    }
414    return false;
415  }
416
417  void Server::disconnectClient(int clientID){
418    ClientInformation *client = clients->findClient(clientID);
419    if(client)
420      disconnectClient(client);
421  }
422  void Server::disconnectClient( ClientInformation *client){
423    connection->disconnectClient(client);
424    gamestates->removeClient(client);
425  }
426 
427}
Note: See TracBrowser for help on using the repository browser.