Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/Masterserver_FS18/src/libraries/network/Server.cc @ 11983

Last change on this file since 11983 was 11829, checked in by mdedial, 7 years ago

WIP 22.03.18: Begin documenting server-side code

  • Property svn:eol-style set to native
File size: 11.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
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/command/Executor.h"
51#include "packet/Chat.h"
52#include "packet/ClassID.h"
53#include "packet/DeleteObjects.h"
54#include "packet/FunctionIDs.h"
55#include "packet/Gamestate.h"
56#include "packet/Welcome.h"
57#include "FunctionCallManager.h"
58#include "GamestateManager.h"
59
60namespace orxonox
61{
62  const unsigned int MAX_FAILURES = 20;
63
64  /**
65  * Constructor for default values (bindaddress is set to ENET_HOST_ANY
66  *
67  */
68  Server::Server()
69  {
70    this->timeSinceLastUpdate_ = 0;
71  }
72
73  /**
74  * Constructor
75  * @param port Port to listen on
76  */
77  Server::Server(int port)
78  {
79    this->setPort(port);
80    this->timeSinceLastUpdate_ = 0;
81  }
82
83  /**
84  * Constructor
85  * @param port Port to listen on
86  * @param bindAddress Address to listen on
87  */
88  Server::Server(int port, const std::string& bindAddress)
89  {
90    this->setPort(port);
91    this->setBindAddress(bindAddress);
92    this->timeSinceLastUpdate_ = 0;
93  }
94
95  /**
96  * @brief Destructor
97  */
98  Server::~Server()
99  {
100  }
101
102  /**
103  * This function opens the server by creating the listener thread
104  */
105  void Server::open()
106  {
107    Host::setActive(true);
108    orxout(verbose, context::network) << "opening server" << endl;
109    this->openListener();
110
111    /* make discoverable on LAN */
112    LANDiscoverable::setActivity(true);
113    LANDiscoverable::updateClientNumber(0);
114
115    /* make discoverable on WAN */
116    WANDiscoverable::setActivity(true);
117    WANDiscoverable::updateClientNumber(0);
118
119    /* done */
120    return;
121  }
122
123  /**
124  * This function closes the server
125  */
126  void Server::close()
127  {
128    Host::setActive(false);
129    orxout(verbose, context::network) << "closing server" << endl;
130    this->disconnectClients();
131    this->closeListener();
132
133    /* tell master server we're closing */
134    orxout(internal_info, context::network) << "disconnecting." << endl;
135    WANDiscoverable::setActivity(false);
136    orxout(internal_info, context::network) << "disconnecting done" << endl;
137
138    LANDiscoverable::setActivity(false);
139    return;
140  }
141
142  /**
143  * Run this function once every tick
144  * calls processQueue and updateGamestate
145  * @param time time since last tick
146  */
147  void Server::update(const Clock& time)
148  {
149    // receive incoming packets
150    Connection::processQueue();
151
152    // receive and process incoming discovery packets
153    LANDiscoverable::update();
154
155    if (GamestateManager::hasPeers())
156    {
157      // process incoming gamestates
158      GamestateManager::processGamestates();
159      FunctionCallManager::processBufferedFunctionCalls();
160
161      // send function calls to clients
162      FunctionCallManager::sendCalls(static_cast<Host*>(this));
163
164      // this steers our network frequency
165      timeSinceLastUpdate_ += time.getDeltaTime();
166      if(timeSinceLastUpdate_ >= NETWORK_PERIOD)
167      {
168        timeSinceLastUpdate_ -= static_cast<unsigned int>(timeSinceLastUpdate_ / NETWORK_PERIOD) * NETWORK_PERIOD;
169        updateGamestate();
170      }
171    }
172  }
173
174  void Server::queuePacket(ENetPacket *packet, int clientID, uint8_t channelID)
175  {
176    ServerConnection::addPacket(packet, clientID, channelID);
177  }
178
179  /**
180   * Return ping time to client in milliseconds.
181   */
182  unsigned int Server::getRTT(unsigned int clientID)
183  {
184    // TODO: Implement
185    return 0;
186  }
187
188  /**
189   * Print ping time to client in milliseconds.
190   */
191  void Server::printRTT()
192  {
193    // TODO: Implement
194  }
195
196  /**
197   * Return packet loss ratio to client (scales from 0 to 1).
198   */
199  float Server::getPacketLoss(unsigned int clientID)
200  {
201    // TODO: Implement
202    return 0.;
203  }
204
205  /**
206   * Take a new snapshot of the gamestate and send it to the clients.
207   */
208  void Server::updateGamestate()
209  {
210    if(this->clientIDs_.size() == 0)
211    {
212      // no client connected
213      return;
214    }
215    GamestateManager::update();
216    sendGameStates();
217    sendObjectDeletes();
218  }
219
220  /**
221   * Send the current gamestate to all peers.
222   */
223  bool Server::sendGameStates()
224  {
225    std::vector<packet::Gamestate*> gamestates = GamestateManager::getGamestates();
226    for(packet::Gamestate* gamestate : gamestates)
227    {
228      gamestate->send(static_cast<Host*>(this));
229    }
230    return true;
231  }
232
233
234  /**
235   * Send 'DeleteObjects' packet
236   */
237  bool Server::sendObjectDeletes()
238  {
239    // no client connected
240    if(this->clientIDs_.size() == 0)
241    {
242      return true;
243    }
244
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
252    del->setPeerID(NETWORK_PEER_ID_BROADCAST);
253    if (!del->send( static_cast<Host*>(this)))
254    {
255      orxout(internal_warning, context::network) << "Server: could not broadcast deleteObjects packet" << endl;
256    }
257
258    // TODO: Possible memory leak?
259    // del is allocated but only deleted if fetchIDs() returns false
260
261    return true;
262  }
263
264  /**
265   * Add a new peer to the server.
266   */
267  void Server::addPeer(uint32_t peerID)
268  {
269    // inform all the listeners
270    this->clientIDs_.push_back(peerID);
271    WANDiscoverable::updateClientNumber(this->clientIDs_.size());
272    LANDiscoverable::updateClientNumber(this->clientIDs_.size());
273
274    ClientConnectionListener::broadcastClientConnected(peerID);
275    GamestateManager::addPeer(peerID);
276
277    orxout(internal_info, context::network) << "Server: added client id: " << peerID << endl;
278
279    createClient(peerID);
280  }
281
282  /**
283   * Remove a peer from the server.
284   */
285  void Server::removePeer(uint32_t peerID)
286  {
287    orxout(verbose, context::network) << "removing client from list" << endl;
288
289    // erase the peer from the list
290    std::vector<uint32_t>::iterator it;
291    for(it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it)
292    {
293      if(*it == peerID)
294      {
295        this->clientIDs_.erase(it);
296        break;
297      }
298    }
299
300    // TODO: What happens if no peer with this ID is found?
301    // Should probably at least log
302
303    WANDiscoverable::updateClientNumber(this->clientIDs_.size());
304    LANDiscoverable::updateClientNumber(this->clientIDs_.size());
305
306    // Send 'clientDisconnected' message
307    ClientConnectionListener::broadcastClientDisconnected(peerID);
308
309    GamestateManager::removePeer(peerID);
310  }
311
312  /**
313   * Process an incoming packet.
314   */
315  void Server::processPacket(packet::Packet* packet)
316  {
317    if(packet->isReliable())
318    {
319      if(this->getLastReceivedGamestateID(packet->getPeerID()) >= packet->getRequiredGamestateID())
320      {
321        packet->process(static_cast<Host*>(this));
322      }
323      else
324      {
325        this->packetQueue_.push_back(packet);
326      }
327    }
328    else
329    {
330      packet->process(static_cast<Host*>(this));
331    }
332  }
333
334  /**
335   * Create a client.
336   */
337  bool Server::createClient(int clientID)
338  {
339
340    // synchronise class ids
341    syncClassid(clientID);
342
343    // now synchronise functionIDs
344    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
345    fIDs->setPeerID(clientID);
346    bool b = fIDs->send(static_cast<Host*>(this));
347    assert(b);
348    // TODO: assert probably isn't the way to go here, as a packet which fails to send will crash the game...
349
350    GamestateManager::setSynched(clientID);
351
352    // Send 'Welcome' packet to client
353    orxout(verbose, context::network) << "sending welcome" << endl;
354    packet::Welcome *w = new packet::Welcome(clientID);
355    w->setPeerID(clientID);
356    b = w->send(static_cast<Host*>(this));
357    assert(b);
358    // TODO: assert probably isn't the way to go here, as a packet which fails to send will crash the game...
359
360    (void)b; // avoid compiler warning
361    return true;
362  }
363
364  /**
365   * Disconnect a client.
366   */
367  void Server::disconnectClient(uint32_t clientID)
368  {
369    ServerConnection::disconnectClient(clientID);
370    GamestateManager::removePeer(clientID);
371  }
372
373  /**
374   * @brief Sends a chat message to the given target ID.
375   * @param message message to be sent
376   * @param sourceID the ID of the sender
377   * @param targetID the ID of the receiver
378   */
379  void Server::doSendChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
380  {
381    // check if the target exists. just ignore the message otherwise
382    if (!this->isValidTarget(targetID)) // TODO: remove this if an invalid clientIDs don't trigger assertions anymore
383    {
384      return;
385    }
386
387    // send the message to the target
388    packet::Chat* packet = new packet::Chat(message, sourceID, targetID);
389    packet->setPeerID(targetID);
390    packet->send(static_cast<Host*>(this));
391
392    // if the target is (or includes) this host as well, call the parent function which passes the message to the listeners
393    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == Host::getPlayerID())
394    {
395      Host::doReceiveChat(message, sourceID, targetID);
396    }
397  }
398
399  /**
400   * @brief Gets called if a packet::Chat packet is received. Forwards the packet to the target
401   * and calls the parent function if necessary.
402   */
403  void Server::doReceiveChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
404  {
405      this->doSendChat(message, sourceID, targetID);
406  }
407
408  /**
409   * @brief Returns true if the target ID is in the list of clients (or if it
410   * corresponds to the broadcast or the server ID).
411   */
412  bool Server::isValidTarget(unsigned int targetID)
413  {
414    // Broadcast or server ID are okay
415    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == NETWORK_PEER_ID_SERVER)
416    {
417      return true;
418    }
419
420    // IDs in the client list are okay also
421    for(uint32_t id : this->clientIDs_)
422    {
423      if(id == targetID)
424      {
425        return true;
426      }
427    }
428
429    return false;
430  }
431
432  void Server::syncClassid(unsigned int clientID)
433  {
434    packet::ClassID *classid = new packet::ClassID();
435    classid->setPeerID(clientID);
436    // TODO: Better to do this with a for loop
437    int failures = 0;
438    while(!classid->send(static_cast<Host*>(this)) && failures < 10)\
439    {
440      failures++;
441    }
442    assert(failures<10);
443    // TODO: assert probably isn't the way to go here, as 10 failed packets will crash the game...
444    orxout(verbose, context::network) << "syncClassid:\tall synchClassID packets have been sent" << endl;
445  }
446
447}
Note: See TracBrowser for help on using the repository browser.