Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/network/Server.cc @ 8829

Last change on this file since 8829 was 8829, checked in by landauf, 13 years ago

enhanced chat system. chat related code is now separated into network-side code (located in Host, Client, Server) and client-side code (located in ChatManager).
note that there are now two chat related listeners: NetworkChatListener, which is used to send chat from the network to ChatManager, and ChatListener, which is used to send online and offline chat from ChatManager to the actual chat interfaces (ChatOverlay, ChatInputHandler, …).
the "chat" console command now supports a second argument which is the clientID of the receiver. this allows private messages (or gameplay messages directed to only one specific player).

  • Property svn:eol-style set to native
File size: 14.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
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/Output.h"
50#include "core/ObjectList.h"
51#include "core/command/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 "ClientInformation.h"
59#include "FunctionCallManager.h"
60#include "GamestateManager.h"
61#include "WANDiscovery.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  {
73    this->timeSinceLastUpdate_=0;
74  }
75
76  Server::Server(int port)
77  {
78    this->setPort( port );
79    this->timeSinceLastUpdate_=0;
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, const std::string& bindAddress)
88  {
89    this->setPort( port );
90    this->setBindAddress( bindAddress );
91    this->timeSinceLastUpdate_=0;
92  }
93
94  /**
95  * @brief Destructor
96  */
97  Server::~Server()
98  {
99  }
100
101
102  /** helper that connects to the master server */
103  void Server::helper_ConnectToMasterserver()
104  {
105//     WANDiscovery::getInstance().msc.sendRequest( MSPROTO_GAME_SERVER " "
106//       MSPROTO_REGISTER_SERVER );
107  }
108
109  /**
110  * This function opens the server by creating the listener thread
111  */
112  void Server::open()
113  {
114    Host::setActive(true);
115    orxout(verbose, context::network) << "opening server" << endl;
116    this->openListener();
117
118    /* make discoverable on LAN */
119    LANDiscoverable::setActivity(true);
120
121    /* make discoverable on WAN */
122    WANDiscoverable::setActivity(true);
123    /* TODO this needs to be optional, we need a switch from the UI to
124     * enable/disable this
125     */
126//     helper_ConnectToMasterserver();
127
128    /* done */
129    return;
130  }
131
132  /**
133  * This function closes the server
134  */
135  void Server::close()
136  {
137    Host::setActive(false);
138    orxout(verbose, context::network) << "closing server" << endl;
139    this->disconnectClients();
140    this->closeListener();
141
142    /* tell master server we're closing */
143    orxout(internal_info, context::network) << "disconnecting." << endl;
144    WANDiscoverable::setActivity(false);
145    orxout(internal_info, context::network) << "disconnecting done" << endl;
146
147    LANDiscoverable::setActivity(false);
148    return;
149  }
150
151  /* handle incoming data */
152  int rephandler( char *addr, ENetEvent *ev )
153  {
154    /* reply to pings */
155    if( !strncmp( (char *)ev->packet->data, MSPROTO_PING_GAMESERVER,
156      MSPROTO_PING_GAMESERVER_LEN ) )
157      //this->msc.sendRequest( MSPROTO_ACK );
158      /* NOTE implement this after pollForReply
159       * reimplementation
160       */
161      return 0;
162
163    /* done handling, return all ok code 0 */
164    return 0;
165  }
166
167  void Server::helper_HandleMasterServerRequests()
168  {
169    /* poll the master server for replies and see whether something
170     * has to be done or changed.
171     */
172    //WANDiscovery::getInstance().msc.pollForReply( rhandler, 10 );
173  }
174
175  /**
176  * Run this function once every tick
177  * calls processQueue and updateGamestate
178  * @param time time since last tick
179  */
180  void Server::update(const Clock& time)
181  {
182    // receive incoming packets
183    Connection::processQueue();
184
185    // receive and process incoming discovery packets
186    LANDiscoverable::update();
187
188    // receive and process requests from master server
189    /* todo */
190    //helper_HandleMasterServerRequests();
191
192    if ( GamestateManager::hasPeers() )
193    {
194      // process incoming gamestates
195      GamestateManager::processGamestates();
196      FunctionCallManager::processBufferedFunctionCalls();
197
198      // send function calls to clients
199      FunctionCallManager::sendCalls( static_cast<Host*>(this) );
200
201      //this steers our network frequency
202      timeSinceLastUpdate_+=time.getDeltaTime();
203      if(timeSinceLastUpdate_>=NETWORK_PERIOD)
204      {
205        timeSinceLastUpdate_ -= static_cast<unsigned int>( timeSinceLastUpdate_ / NETWORK_PERIOD ) * NETWORK_PERIOD;
206        updateGamestate();
207      }
208//       sendPackets(); // flush the enet queue
209    }
210  }
211
212  void Server::queuePacket(ENetPacket *packet, int clientID, uint8_t channelID)
213  {
214    ServerConnection::addPacket(packet, clientID, channelID);
215  }
216
217  /**
218   * @brief: returns ping time to client in milliseconds
219   */
220  unsigned int Server::getRTT(unsigned int clientID)
221  {
222//     assert(ClientInformation::findClient(clientID));
223//     return ClientInformation::findClient(clientID)->getRTT();
224    // TODO: reimplement
225    return 0;
226  }
227
228  void Server::printRTT()
229  {
230//     for( ClientInformation* temp=ClientInformation::getBegin(); temp!=0; temp=temp->next() )
231//       orxout(message) << "Round trip time to client with ID: " << temp->getID() << " is " << temp->getRTT() << " ms" << endl;
232  }
233
234  /**
235   * @brief: return packet loss ratio to client (scales from 0 to 1)
236   */
237  float Server::getPacketLoss(unsigned int clientID)
238  {
239//     assert(ClientInformation::findClient(clientID));
240//     return ClientInformation::findClient(clientID)->getPacketLoss();
241    return 0.;
242  }
243
244  /**
245  * takes a new snapshot of the gamestate and sends it to the clients
246  */
247  void Server::updateGamestate()
248  {
249    if( this->clientIDs_.size()==0 )
250      //no client connected
251      return;
252    GamestateManager::update();
253//     orxout(verbose_more, context::network) << "Server: one gamestate update complete, goig to sendGameState" << endl;
254    //orxout(verbose_more, context::network) << "updated gamestate, sending it" << endl;
255    //if(clients->getGamestateID()!=GAMESTATEID_INITIAL)
256    sendGameStates();
257    sendObjectDeletes();
258//     orxout(verbose_more, context::network) << "Server: one sendGameState turn complete, repeat in next tick" << endl;
259    //orxout(verbose_more, context::network) << "sent gamestate" << endl;
260  }
261
262  /**
263  * sends the current gamestate to all peers
264  */
265  bool Server::sendGameStates()
266  {
267    std::vector<packet::Gamestate*> gamestates = GamestateManager::getGamestates();
268    std::vector<packet::Gamestate*>::iterator it;
269    for( it = gamestates.begin(); it != gamestates.end(); ++it )
270    {
271      (*it)->send(static_cast<Host*>(this));
272    }
273    return true;
274  }
275
276
277  bool Server::sendObjectDeletes()
278  {
279//     ClientInformation *temp = ClientInformation::getBegin();
280//     if( temp == NULL )
281      //no client connected
282    if( this->clientIDs_.size()==0 )
283      return true;
284    packet::DeleteObjects *del = new packet::DeleteObjects();
285    if(!del->fetchIDs())
286    {
287      delete del;
288      return true;  //everything ok (no deletes this tick)
289    }
290//     orxout(verbose, context::network) << "sending DeleteObjects" << endl;
291//     while(temp != NULL){
292//       if( !(temp->getSynched()) )
293//       {
294//         orxout(verbose_more, context::network) << "Server: not sending gamestate" << endl;
295//         temp=temp->next();
296//         continue;
297//       }
298//       int cid = temp->getID(); //get client id
299//       packet::DeleteObjects *cd = new packet::DeleteObjects(*del);
300//       assert(cd);
301    del->setPeerID(NETWORK_PEER_ID_BROADCAST);
302    if ( !del->send( static_cast<Host*>(this) ) )
303      orxout(internal_warning, context::network) << "Server: could not broadcast deleteObjects packet" << endl;
304//       temp=temp->next();
305      // gs gets automatically deleted by enet callback
306//     }
307//     delete del;
308    return true;
309  }
310
311
312  void Server::addPeer(uint32_t peerID)
313  {
314//     static unsigned int newid=1;
315//
316//     orxout(internal_info, context::network) << "Server: adding client" << endl;
317//     ClientInformation *temp = ClientInformation::insertBack(new ClientInformation);
318//     if(!temp)
319//     {
320//       orxout(internal_warning, context::network) << "Server: could not add client" << endl;
321//     }
322//     temp->setID(newid);
323//     temp->setPeer(event->peer);
324
325    // inform all the listeners
326    this->clientIDs_.push_back(peerID);
327    ClientConnectionListener::broadcastClientConnected(peerID);
328    GamestateManager::addPeer(peerID);
329
330//     ++newid;
331
332    orxout(internal_info, context::network) << "Server: added client id: " << peerID << endl;
333    createClient(peerID);
334}
335
336  void Server::removePeer(uint32_t peerID)
337  {
338    orxout(verbose, context::network) << "removing client from list" << endl;
339//     ClientInformation *client = ClientInformation::findClient(&event->peer->address);
340//     if(!client)
341//       return;
342//     else
343//     {
344  std::vector<uint32_t>::iterator it;
345  for( it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it )
346  {
347    if( *it == peerID )
348    {
349      this->clientIDs_.erase(it);
350      break;
351    }
352  }
353  ClientConnectionListener::broadcastClientDisconnected(peerID);
354  GamestateManager::removePeer(peerID);
355      //ServerConnection::disconnectClient( client );
356      //ClientConnectionListener::broadcastClientDisconnected( client->getID() ); //this is done in ClientInformation now
357//       delete client;
358//     }
359  }
360
361  void Server::processPacket(packet::Packet* packet)
362  {
363    if( packet->isReliable() )
364    {
365      if( this->getLastReceivedGamestateID(packet->getPeerID()) >= packet->getRequiredGamestateID() )
366        packet->process(static_cast<Host*>(this));
367      else
368        this->packetQueue_.push_back(packet);
369    }
370    else
371      packet->process(static_cast<Host*>(this));
372  }
373
374
375  bool Server::createClient(int clientID)
376  {
377//     ClientInformation *temp = ClientInformation::findClient(clientID);
378//     if(!temp)
379//     {
380//       orxout(internal_error, context::network) << "Server. could not create client with id: " << clientID << endl;
381//       return false;
382//     }
383//     orxout(verbose, context::network) << "Con.Man: creating client id: " << temp->getID() << endl;
384
385    // synchronise class ids
386    syncClassid(clientID);
387
388    // now synchronise functionIDs
389    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
390    fIDs->setPeerID(clientID);
391    bool b = fIDs->send( static_cast<Host*>(this) );
392    assert(b);
393
394//     temp->setSynched(true);
395    GamestateManager::setSynched(clientID);
396
397    orxout(verbose, context::network) << "sending welcome" << endl;
398    packet::Welcome *w = new packet::Welcome(clientID);
399    w->setPeerID(clientID);
400    b = w->send( static_cast<Host*>(this) );
401    assert(b);
402//     packet::Gamestate *g = new packet::Gamestate();
403//     g->setPeerID(clientID);
404//     b = g->collectData(0,packet::GAMESTATE_MODE_SERVER);
405//     assert(b);
406//     if(!b)
407//       return false; //no data for the client
408// //     b = g->compressData();
409// //     assert(b);
410//     b = g->send( static_cast<Host*>(this) );
411//     assert(b);
412    return true;
413  }
414
415  void Server::disconnectClient( uint32_t clientID )
416  {
417    ServerConnection::disconnectClient( clientID );
418    GamestateManager::removePeer( clientID );
419    // inform all the listeners
420    // ClientConnectionListener::broadcastClientDisconnected(client->getID()); // this is done in ClientInformation now
421  }
422
423  /**
424   * @brief Sends a chat message to the given target ID.
425   * @param message message to be sent
426   * @param sourceID the ID of the sender
427   * @param targetID the ID of the receiver
428   */
429  void Server::doSendChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
430  {
431    // check if the target exists. just ignore the message otherwise
432    if (!this->isValidTarget(targetID)) // TODO: remove this if an invalid clientIDs don't trigger assertions anymore
433      return;
434
435    // send the message to the target
436    packet::Chat* packet = new packet::Chat(message, sourceID, targetID);
437    packet->setPeerID(targetID);
438    packet->send( static_cast<Host*>(this) );
439
440    // if the target is (or includes) this host as well, call the parent function which passes the message to the listeners
441    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == Host::getPlayerID())
442      Host::doReceiveChat(message, sourceID, targetID);
443  }
444
445  /**
446   * @brief Gets called if a packet::Chat packet is received. Forwards the packet to the target
447   * and calls the parent function if necessary.
448   */
449  void Server::doReceiveChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
450  {
451      this->doSendChat(message, sourceID, targetID);
452  }
453
454  /**
455   * @brief Returns true if the target ID is in the list of clients (or if it
456   * corresponds to the broadcast or the server ID).
457   */
458  bool Server::isValidTarget(unsigned int targetID)
459  {
460    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == NETWORK_PEER_ID_SERVER)
461      return true;
462
463    std::vector<uint32_t>::iterator it;
464    for( it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it )
465      if( *it == targetID )
466        return true;
467
468    return false;
469  }
470
471  void Server::syncClassid(unsigned int clientID)
472  {
473    int failures=0;
474    packet::ClassID *classid = new packet::ClassID();
475    classid->setPeerID(clientID);
476    while(!classid->send( static_cast<Host*>(this) ) && failures < 10){
477      failures++;
478    }
479    assert(failures<10);
480    orxout(verbose, context::network) << "syncClassid:\tall synchClassID packets have been sent" << endl;
481  }
482
483}
Note: See TracBrowser for help on using the repository browser.