Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/network/Server.cc @ 5958

Last change on this file since 5958 was 5929, checked in by rgrieder, 15 years ago

Merged core5 branch back to the trunk.
Key features include clean level unloading and an extended XML event system.

Two important notes:
Delete your keybindings.ini files! * or you will still get parser errors when loading the key bindings.
Delete build_dir/lib/modules/libgamestates.module! * or orxonox won't start.
Best thing to do is to delete the build folder ;)

  • Property svn:eol-style set to native
File size: 11.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
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#define WIN32_LEAN_AND_MEAN
44#include <enet/enet.h>
45#include <cassert>
46#include <string>
47
48#include "util/Clock.h"
49#include "util/Debug.h"
50#include "core/ObjectList.h"
51#include "core/Executor.h"
52#include "packet/Chat.h"
53#include "packet/ClassID.h"
54#include "packet/DeleteObjects.h"
55#include "packet/FunctionIDs.h"
56#include "packet/Gamestate.h"
57#include "packet/Welcome.h"
58#include "ChatListener.h"
59#include "ClientInformation.h"
60#include "FunctionCallManager.h"
61#include "GamestateManager.h"
62
63namespace orxonox
64{
65  const unsigned int MAX_FAILURES = 20;
66
67  /**
68  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
69  *
70  */
71  Server::Server() {
72    this->timeSinceLastUpdate_=0;
73  }
74
75  Server::Server(int port){
76    this->setPort( port );
77    this->timeSinceLastUpdate_=0;
78  }
79
80  /**
81  * Constructor
82  * @param port Port to listen on
83  * @param bindAddress Address to listen on
84  */
85  Server::Server(int port, const std::string& bindAddress) {
86    this->setPort( port );
87    this->setBindAddress( bindAddress );
88    this->timeSinceLastUpdate_=0;
89  }
90
91  /**
92  * @brief Destructor
93  */
94  Server::~Server(){
95  }
96
97  /**
98  * This function opens the server by creating the listener thread
99  */
100  void Server::open() {
101    COUT(4) << "opening server" << endl;
102    this->openListener();
103    return;
104  }
105
106  /**
107  * This function closes the server
108  */
109  void Server::close() {
110    COUT(4) << "closing server" << endl;
111    this->disconnectClients();
112    this->closeListener();
113    return;
114  }
115
116  bool Server::processChat(const std::string& message, unsigned int playerID){
117    ClientInformation *temp = ClientInformation::getBegin();
118    packet::Chat *chat;
119    while(temp){
120      chat = new packet::Chat(message, playerID);
121      chat->setClientID(temp->getID());
122      if(!chat->send())
123        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
124      temp = temp->next();
125    }
126//    COUT(1) << "Player " << playerID << ": " << message << std::endl;
127    return true;
128  }
129
130
131  /**
132  * Run this function once every tick
133  * calls processQueue and updateGamestate
134  * @param time time since last tick
135  */
136  void Server::update(const Clock& time) {
137    // receive incoming packets
138    Connection::processQueue();
139   
140    if ( ClientInformation::hasClients() )
141    {
142      // process incoming gamestates
143      GamestateManager::processGamestates();
144     
145      // send function calls to clients
146      FunctionCallManager::sendCalls();
147     
148      //this steers our network frequency
149      timeSinceLastUpdate_+=time.getDeltaTime();
150      if(timeSinceLastUpdate_>=NETWORK_PERIOD)
151      {
152        timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
153        updateGamestate();
154      }
155      sendPackets(); // flush the enet queue
156    }
157  }
158
159  bool Server::queuePacket(ENetPacket *packet, int clientID){
160    return ServerConnection::addPacket(packet, clientID);
161  }
162 
163  /**
164   * @brief: returns ping time to client in milliseconds
165   */
166  unsigned int Server::getPing(unsigned int clientID){
167    assert(ClientInformation::findClient(clientID));
168    return ClientInformation::findClient(clientID)->getRTT();
169  }
170
171  /**
172   * @brief: return packet loss ratio to client (scales from 0 to 1)
173   */
174  double Server::getPacketLoss(unsigned int clientID){
175    assert(ClientInformation::findClient(clientID));
176    return ClientInformation::findClient(clientID)->getPacketLoss();
177  }
178
179  /**
180  * takes a new snapshot of the gamestate and sends it to the clients
181  */
182  void Server::updateGamestate() {
183    if( ClientInformation::getBegin()==NULL )
184      //no client connected
185      return;
186    GamestateManager::update();
187    COUT(5) << "Server: one gamestate update complete, goig to sendGameState" << std::endl;
188    //std::cout << "updated gamestate, sending it" << std::endl;
189    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
190    sendGameState();
191    sendObjectDeletes();
192    COUT(5) << "Server: one sendGameState turn complete, repeat in next tick" << std::endl;
193    //std::cout << "sent gamestate" << std::endl;
194  }
195
196  bool Server::processPacket( ENetPacket *packet, ENetPeer *peer ){
197    packet::Packet *p = packet::Packet::createPacket(packet, peer);
198    return p->process();
199  }
200
201  /**
202  * sends the gamestate
203  */
204  bool Server::sendGameState() {
205//     COUT(5) << "Server: starting function sendGameState" << std::endl;
206//     ClientInformation *temp = ClientInformation::getBegin();
207//     bool added=false;
208//     while(temp != NULL){
209//       if( !(temp->getSynched()) ){
210//         COUT(5) << "Server: not sending gamestate" << std::endl;
211//         temp=temp->next();
212//         if(!temp)
213//           break;
214//         continue;
215//       }
216//       COUT(4) << "client id: " << temp->getID() << " RTT: " << temp->getRTT() << " loss: " << temp->getPacketLoss() << std::endl;
217//       COUT(5) << "Server: doing gamestate gamestate preparation" << std::endl;
218//       int cid = temp->getID(); //get client id
219//       packet::Gamestate *gs = GamestateManager::popGameState(cid);
220//       if(gs==NULL){
221//         COUT(2) << "Server: could not generate gamestate (NULL from compress)" << std::endl;
222//         temp = temp->next();
223//         continue;
224//       }
225//       //std::cout << "adding gamestate" << std::endl;
226//       gs->setClientID(cid);
227//       if ( !gs->send() ){
228//         COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
229//         temp->addFailure();
230//       }else
231//         temp->resetFailures();
232//       added=true;
233//       temp=temp->next();
234//       // gs gets automatically deleted by enet callback
235//     }
236    GamestateManager::sendGamestates();
237    return true;
238  }
239
240  bool Server::sendObjectDeletes(){
241    ClientInformation *temp = ClientInformation::getBegin();
242    if( temp == NULL )
243      //no client connected
244      return true;
245    packet::DeleteObjects *del = new packet::DeleteObjects();
246    if(!del->fetchIDs())
247    {
248      delete del;
249      return true;  //everything ok (no deletes this tick)
250    }
251//     COUT(3) << "sending DeleteObjects" << std::endl;
252    while(temp != NULL){
253      if( !(temp->getSynched()) ){
254        COUT(5) << "Server: not sending gamestate" << std::endl;
255        temp=temp->next();
256        continue;
257      }
258      int cid = temp->getID(); //get client id
259      packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
260      assert(cd);
261      cd->setClientID(cid);
262      if ( !cd->send() )
263        COUT(3) << "Server: packet with client id (cid): " << cid << " not sended: " << temp->getFailures() << std::endl;
264      temp=temp->next();
265      // gs gets automatically deleted by enet callback
266    }
267    delete del;
268    return true;
269  }
270
271
272  void Server::addPeer(ENetEvent *event){
273    static unsigned int newid=1;
274
275    COUT(2) << "Server: adding client" << std::endl;
276    ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
277    if(!temp){
278      COUT(2) << "Server: could not add client" << std::endl;
279    }
280    temp->setID(newid);
281    temp->setPeer(event->peer);
282
283    // inform all the listeners
284    ClientConnectionListener::broadcastClientConnected(newid);
285
286    ++newid;
287
288    COUT(3) << "Server: added client id: " << temp->getID() << std::endl;
289    createClient(temp->getID());
290}
291
292  void Server::removePeer(ENetEvent *event)
293  {
294    COUT(4) << "removing client from list" << std::endl;
295    ClientInformation *client = ClientInformation::findClient(&event->peer->address);
296    if(!client)
297      return;
298    else
299    {
300      //ServerConnection::disconnectClient( client );
301      ClientConnectionListener::broadcastClientDisconnected( client->getID() );
302      delete client;
303    }
304  }
305
306  bool Server::createClient(int clientID){
307    ClientInformation *temp = ClientInformation::findClient(clientID);
308    if(!temp){
309      COUT(2) << "Conn.Man. could not create client with id: " << clientID << std::endl;
310      return false;
311    }
312    COUT(5) << "Con.Man: creating client id: " << temp->getID() << std::endl;
313   
314    // synchronise class ids
315    syncClassid(temp->getID());
316   
317    // now synchronise functionIDs
318    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
319    fIDs->setClientID(clientID);
320    bool b = fIDs->send();
321    assert(b);
322   
323    temp->setSynched(true);
324    COUT(4) << "sending welcome" << std::endl;
325    packet::Welcome *w = new packet::Welcome(temp->getID(), temp->getShipID());
326    w->setClientID(temp->getID());
327    b = w->send();
328    assert(b);
329    packet::Gamestate *g = new packet::Gamestate();
330    g->setClientID(temp->getID());
331    b = g->collectData(0,0x1);
332    if(!b)
333      return false; //no data for the client
334    b = g->compressData();
335    assert(b);
336    b = g->send();
337    assert(b);
338    return true;
339  }
340 
341  void Server::disconnectClient( ClientInformation *client ){
342    ServerConnection::disconnectClient( client );
343    GamestateManager::removeClient(client);
344    // inform all the listeners
345    ClientConnectionListener::broadcastClientDisconnected(client->getID());
346  }
347
348  bool Server::chat(const std::string& message){
349      return this->sendChat(message, Host::getPlayerID());
350  }
351
352  bool Server::broadcast(const std::string& message){
353      return this->sendChat(message, CLIENTID_UNKNOWN);
354  }
355
356  bool Server::sendChat(const std::string& message, unsigned int clientID){
357    ClientInformation *temp = ClientInformation::getBegin();
358    packet::Chat *chat;
359    while(temp){
360      chat = new packet::Chat(message, clientID);
361      chat->setClientID(temp->getID());
362      if(!chat->send())
363        COUT(3) << "could not send Chat message to client ID: " << temp->getID() << std::endl;
364      temp = temp->next();
365    }
366//    COUT(1) << "Player " << Host::getPlayerID() << ": " << message << std::endl;
367    for (ObjectList<ChatListener>::iterator it = ObjectList<ChatListener>::begin(); it != ObjectList<ChatListener>::end(); ++it)
368      it->incomingChat(message, clientID);
369
370    return true;
371  }
372
373  void Server::syncClassid(unsigned int clientID) {
374    int failures=0;
375    packet::ClassID *classid = new packet::ClassID();
376    classid->setClientID(clientID);
377    while(!classid->send() && failures < 10){
378      failures++;
379    }
380    assert(failures<10);
381    COUT(4) << "syncClassid:\tall synchClassID packets have been sent" << std::endl;
382  }
383
384}
Note: See TracBrowser for help on using the repository browser.