Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core3/src/network/Server.cc @ 1996

Last change on this file since 1996 was 1591, checked in by landauf, 16 years ago

Again some heavy changes in ObjectList and Iterator:
there are now two types of iterators:

Iterator<ClassName> can iterate through any objectlist, either given by ObjectList<AnyClassName>::begin() or anyidentifier→getObjects()→begin(). Important note Iterator<ClassName> uses dynamic_cast.
And yes, it's possible to do this: Iterator<WorldEntity> it = ObjectList<SpaceShip>::begin()

ObjectList<ClassName>::iterator is the second iterator - it uses the ObjectList in a templated manner and therefore doesn't need dynamic_cast. But the only thing you can do is iterating through exactly the right ObjectList: ObjectList<ClassName>::iterator it = ObjectList<ClassName>::begin(). Anything else fails.

Those changes bring, at my system, something around +12% FPS compared with trunk and +25% FPS compared with the last revision of core3. Although I have to admit the FPS gain is only that high because iterating through objects is the main thing we're doing ingame right now. It would look totally different with physics, sound, AI, scripts, triggers and so on.

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