Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/Server.cc @ 1494

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