Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1535 was 1534, checked in by rgrieder, 16 years ago

merged network branch back to trunk

  • Property svn:eol-style set to native
File size: 13.0 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_-=(1./NETWORK_FREQUENCY);
184      gamestates->processGameStates();
185      updateGamestate();
186    }
187//     usleep(5000); // TODO remove
188    return;
189  }
190
191  /**
192  * processes all the packets waiting in the queue
193  */
194  void Server::processQueue() {
195    ENetEvent *event;
196    int clientID=-1;
197    while(!connection->queueEmpty()){
198      //std::cout << "Client " << clientID << " sent: " << std::endl;
199      //clientID here is a reference to grab clientID from ClientInformation
200      event = connection->getEvent();
201      if(!event)
202        continue;
203      assert(event->type != ENET_EVENT_TYPE_NONE);
204      switch( event->type ) {
205      case ENET_EVENT_TYPE_CONNECT:
206        COUT(3) << "processing event_Type_connect" << std::endl;
207        addClient(event);
208        break;
209      case ENET_EVENT_TYPE_DISCONNECT:
210        if(clients->findClient(&event->peer->address))
211          disconnectClient(event);
212        break;
213      case ENET_EVENT_TYPE_RECEIVE:
214        if(clients->findClient(&event->peer->address)){
215          clientID = clients->findClient(&event->peer->address)->getID();
216          if( !elaborate(event->packet, clientID) ) 
217            COUT(3) << "Server: could not elaborate" << std::endl;
218        }
219        break;
220      }
221      delete event;
222      //if statement to catch case that packetbuffer is empty
223    }
224  }
225
226  /**
227  * takes a new snapshot of the gamestate and sends it to the clients
228  */
229  void Server::updateGamestate() {
230    gamestates->update();
231    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
232    //std::cout << "updated gamestate, sending it" << std::endl;
233    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
234    sendGameState();
235    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
236    //std::cout << "sent gamestate" << std::endl;
237  }
238
239  /**
240  * sends the gamestate
241  */
242  bool Server::sendGameState() {
243    COUT(5) << "Server: starting function sendGameState" << std::endl;
244    ClientInformation *temp = clients;
245    bool added=false;
246    while(temp != NULL){
247      if(temp->getHead()){
248        temp=temp->next();
249        //think this works without continue
250        continue;
251      }
252      if( !(temp->getSynched()) ){
253        COUT(5) << "Server: not sending gamestate" << std::endl;
254        temp=temp->next();
255        //think this works without continue
256        continue;
257      }
258      COUT(4) << "client id: " << temp->getID() << " RTT: " << temp->getRTT() << " loss: " << temp->getPacketLoss() << std::endl;
259      COUT(5) << "Server: doing gamestate gamestate preparation" << std::endl;
260      int gid = temp->getGamestateID(); //get gamestate id
261      int cid = temp->getID(); //get client id
262      COUT(5) << "Server: got acked (gamestate) ID from clientlist: " << gid << std::endl;
263      GameStateCompressed *gs = gamestates->popGameState(cid);
264      if(gs==NULL){
265        COUT(2) << "Server: could not generate gamestate (NULL from compress)" << std::endl;
266        continue;
267      }
268      //std::cout << "adding gamestate" << std::endl;
269      ENetPacket *packet = packet_gen.gstate(gs);
270      if(!packet)
271        continue;
272      if ( !(connection->addPacket(packet, cid)) ){
273        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl; 
274        temp->addFailure();
275        /*if(temp->getFailures() > 0 )
276          disconnectClient(temp);*/
277      //std::cout << "added gamestate" << std::endl;
278      }else
279        temp->resetFailures();
280      added=true;
281      temp=temp->next();
282      // now delete gamestate
283      delete[] gs->data;
284      delete gs;
285    }
286    /*if(added) {
287      //std::cout << "send gamestates from server.cc in sendGameState" << std::endl;
288      return connection->sendPackets();
289    }*/
290    //COUT(5) << "Server: had no gamestates to send" << std::endl;
291    return true;
292  }
293
294  void Server::processAck( ack *data, int clientID) {
295    COUT(4) << "Server: processing ack from client: " << clientID << "; ack-id: " << data->a << std::endl;
296    gamestates->ackGameState(clientID, data->a);
297    delete data;
298  }
299 
300  bool Server::processConnectRequest( connectRequest *con, int clientID ){
301    //(COUT(3) << "processing connectRequest " << std::endl;
302    //connection->addPacket(packet_gen.gstate(gamestates->popGameState(clientID)) , clientID);
303    //createClient(clientID);
304    delete con;
305    return true;
306  }
307 
308  void Server::processGamestate( GameStateCompressed *data, int clientID){
309    COUT(4) << "processing partial gamestate from client " << clientID << std::endl;
310    gamestates->addGameState(data, clientID);
311        /*COUT(3) << "Could not push gamestate\t\t\t\t=====" << std::endl;
312    else
313      if(clients->findClient(clientID))
314        clients->findClient(clientID)->resetFailures();*/
315  }
316 
317  void Server::processChat( chat *data, int clientId){
318    char *message = new char [strlen(data->message)+10+1];
319    sprintf(message, "Player %d: %s", clientId, data->message);
320    COUT(1) << message << std::endl;
321    ENetPacket *pck = packet_gen.chatMessage(message);
322    connection->addPacketAll(pck);
323    delete[] data->message;
324    delete data;
325  }
326 
327  bool Server::addClient(ENetEvent *event){
328    ClientInformation *temp = clients->insertBack(new ClientInformation);
329    if(!temp){
330      COUT(2) << "Server: could not add client" << std::endl;
331      return false;
332    }
333    if(temp->prev()->getHead()) { //not good if you use anything else than insertBack
334      temp->prev()->setID(0); //bugfix: not necessary but usefull
335      temp->setID(1);
336    }
337    else
338      temp->setID(temp->prev()->getID()+1);
339    temp->setPeer(event->peer);
340    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
341    return createClient(temp->getID());
342  }
343 
344  bool Server::createClient(int clientID){
345    ClientInformation *temp = clients->findClient(clientID);
346    if(!temp){
347      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
348      return false;
349    }
350    COUT(4) << "Con.Man: creating client id: " << temp->getID() << std::endl;
351    connection->syncClassid(temp->getID());
352    COUT(5) << "creating spaceship for clientid: " << temp->getID() << std::endl;
353    // TODO: this is only a hack, untill we have a possibility to define default player-join actions
354    if(!createShip(temp))
355      COUT(2) << "Con.Man. could not create ship for clientid: " << clientID << std::endl;
356    else
357      COUT(3) << "created spaceship" << std::endl;
358    temp->setSynched(true);
359    COUT(3) << "sending welcome" << std::endl;
360    connection->sendWelcome(temp->getID(), temp->getShipID(), true);
361    return true;
362  }
363 
364  bool Server::createShip(ClientInformation *client){
365    if(!client)
366      return false;
367    orxonox::Identifier* id = ID("SpaceShip");
368    if(!id){
369      COUT(4) << "We could not create the SpaceShip for client: " << client->getID() << std::endl;
370      return false;
371    }
372    orxonox::SpaceShip *no = dynamic_cast<orxonox::SpaceShip *>(id->fabricate());
373    no->setPosition(orxonox::Vector3(0,0,80));
374    no->setScale(10);
375    //no->setYawPitchRoll(orxonox::Degree(-90),orxonox::Degree(-90),orxonox::Degree(0));
376    no->setMesh("assff.mesh");
377    no->setMaxSpeed(500);
378    no->setMaxSideAndBackSpeed(50);
379    no->setMaxRotation(1.0);
380    no->setTransAcc(200);
381    no->setRotAcc(3.0);
382    no->setTransDamp(75);
383    no->setRotDamp(1.0);
384    no->setCamera("cam_"+client->getID());
385    no->classID = id->getNetworkID();
386    no->create();
387   
388    client->setShipID(no->objectID);
389    return true;
390  }
391 
392  bool Server::disconnectClient(ENetEvent *event){
393    COUT(4) << "removing client from list" << std::endl;
394    //return removeClient(head_->findClient(&(peer->address))->getID());
395   
396    //boost::recursive_mutex::scoped_lock lock(head_->mutex_);
397    orxonox::Iterator<orxonox::SpaceShip> it = orxonox::ObjectList<orxonox::SpaceShip>::start();
398    ClientInformation *client = clients->findClient(&event->peer->address);
399    if(!client)
400      return false;
401    while(it){
402      if(it->objectID!=client->getShipID()){
403        ++it;
404        continue;
405      }
406      orxonox::Iterator<orxonox::SpaceShip> temp=it;
407      ++it;
408      delete  *temp;
409      return clients->removeClient(event->peer);
410    }
411    return false;
412  }
413
414  void Server::disconnectClient(int clientID){
415    ClientInformation *client = clients->findClient(clientID);
416    if(client)
417      disconnectClient(client);
418  }
419  void Server::disconnectClient( ClientInformation *client){
420    connection->disconnectClient(client);
421    gamestates->removeClient(client);
422  }
423 
424}
Note: See TracBrowser for help on using the repository browser.