Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ceguilua/src/network/Server.cc @ 1809

Last change on this file since 1809 was 1785, checked in by rgrieder, 16 years ago

replaced the macro constants with c++'s idea of constants in network library.

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