Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file was 12027, checked in by merholzl, 6 years ago

Merged Masterserver, refresh button had to be removed

  • Property svn:eol-style set to native
File size: 10.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/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        this->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   * Print ping time to client in milliseconds.
181   */
182  void Server::printRTT()
183  {
184    // TODO: Implement
185  }
186
187  /**
188   * Take a new snapshot of the gamestate and send it to the clients.
189   */
190  void Server::updateGamestate()
191  {
192    if(this->clientIDs_.size() == 0)
193    {
194      // no client connected
195      return;
196    }
197    GamestateManager::update();
198    this->sendGameStates();
199    this->sendObjectDeletes();
200  }
201
202  /**
203   * Send the current gamestate to all peers.
204   */
205  bool Server::sendGameStates()
206  {
207    std::vector<packet::Gamestate*> gamestates = GamestateManager::getGamestates();
208    for(packet::Gamestate* gamestate : gamestates)
209    {
210      gamestate->send(static_cast<Host*>(this));
211    }
212    return true;
213  }
214
215
216  /**
217   * Send 'DeleteObjects' packet
218   */
219  bool Server::sendObjectDeletes()
220  {
221    // no client connected
222    if(this->clientIDs_.size() == 0)
223    {
224      return true;
225    }
226
227    packet::DeleteObjects *del = new packet::DeleteObjects();
228    if(!del->fetchIDs())
229    {
230      delete del;
231      return true;  //everything ok (no deletes this tick)
232    }
233
234    del->setPeerID(NETWORK_PEER_ID_BROADCAST);
235    if (!del->send( static_cast<Host*>(this)))
236    {
237      orxout(internal_warning, context::network) << "Server: could not broadcast deleteObjects packet" << endl;
238    }
239
240    return true;
241  }
242
243  /**
244   * Add a new peer to the server.
245   */
246  void Server::addPeer(uint32_t peerID)
247  {
248    // inform all the listeners
249    this->clientIDs_.push_back(peerID);
250    WANDiscoverable::updateClientNumber(this->clientIDs_.size());
251    LANDiscoverable::updateClientNumber(this->clientIDs_.size());
252
253    ClientConnectionListener::broadcastClientConnected(peerID);
254    GamestateManager::addPeer(peerID);
255
256    orxout(internal_info, context::network) << "Server: added client id: " << peerID << endl;
257
258    this->createClient(peerID);
259  }
260
261  /**
262   * Remove a peer from the server.
263   */
264  void Server::removePeer(uint32_t peerID)
265  {
266    orxout(verbose, context::network) << "removing client from list" << endl;
267
268    // erase the peer from the list
269    std::vector<uint32_t>::iterator it;
270    for(it=this->clientIDs_.begin(); it!=this->clientIDs_.end(); ++it)
271    {
272      if(*it == peerID)
273      {
274        this->clientIDs_.erase(it);
275        break;
276      }
277    }
278
279    WANDiscoverable::updateClientNumber(this->clientIDs_.size());
280    LANDiscoverable::updateClientNumber(this->clientIDs_.size());
281
282    // Send 'clientDisconnected' message
283    ClientConnectionListener::broadcastClientDisconnected(peerID);
284
285    GamestateManager::removePeer(peerID);
286  }
287
288  /**
289   * Process an incoming packet.
290   */
291  void Server::processPacket(packet::Packet* packet)
292  {
293    if(packet->isReliable())
294    {
295      if(this->getLastReceivedGamestateID(packet->getPeerID()) >= packet->getRequiredGamestateID())
296      {
297        packet->process(static_cast<Host*>(this));
298      }
299      else
300      {
301        this->packetQueue_.push_back(packet);
302      }
303    }
304    else
305    {
306      packet->process(static_cast<Host*>(this));
307    }
308  }
309
310  /**
311   * Create a client.
312   */
313  bool Server::createClient(int clientID)
314  {
315
316    // synchronise class ids
317    this->syncClassid(clientID);
318
319    // now synchronise functionIDs
320    packet::FunctionIDs *fIDs = new packet::FunctionIDs();
321    fIDs->setPeerID(clientID);
322    bool b = fIDs->send(static_cast<Host*>(this));
323    assert(b);
324
325    GamestateManager::setSynched(clientID);
326
327    // Send 'Welcome' packet to client
328    orxout(verbose, context::network) << "sending welcome" << endl;
329    packet::Welcome *w = new packet::Welcome(clientID);
330    w->setPeerID(clientID);
331    b = w->send(static_cast<Host*>(this));
332    assert(b);
333
334    (void)b; // avoid compiler warning
335    return true;
336  }
337
338  /**
339   * Disconnect a client.
340   */
341  void Server::disconnectClient(uint32_t clientID)
342  {
343    ServerConnection::disconnectClient(clientID);
344    GamestateManager::removePeer(clientID);
345  }
346
347  /**
348   * @brief Sends a chat message to the given target ID.
349   * @param message message to be sent
350   * @param sourceID the ID of the sender
351   * @param targetID the ID of the receiver
352   */
353  void Server::doSendChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
354  {
355    // check if the target exists. just ignore the message otherwise
356    if (!this->isValidTarget(targetID))
357    {
358      return;
359    }
360
361    // send the message to the target
362    packet::Chat* packet = new packet::Chat(message, sourceID, targetID);
363    packet->setPeerID(targetID);
364    packet->send(static_cast<Host*>(this));
365
366    // if the target is (or includes) this host as well, call the parent function which passes the message to the listeners
367    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == Host::getPlayerID())
368    {
369      Host::doReceiveChat(message, sourceID, targetID);
370    }
371  }
372
373  /**
374   * @brief Gets called if a packet::Chat packet is received. Forwards the packet to the target
375   * and calls the parent function if necessary.
376   */
377  void Server::doReceiveChat(const std::string& message, unsigned int sourceID, unsigned int targetID)
378  {
379      this->doSendChat(message, sourceID, targetID);
380  }
381
382  /**
383   * @brief Returns true if the target ID is in the list of clients (or if it
384   * corresponds to the broadcast or the server ID).
385   */
386  bool Server::isValidTarget(unsigned int targetID)
387  {
388    // Broadcast or server ID are okay
389    if (targetID == NETWORK_PEER_ID_BROADCAST || targetID == NETWORK_PEER_ID_SERVER)
390    {
391      return true;
392    }
393
394    // IDs in the client list are okay also
395    for(uint32_t id : this->clientIDs_)
396    {
397      if(id == targetID)
398      {
399        return true;
400      }
401    }
402
403    return false;
404  }
405
406  void Server::syncClassid(unsigned int clientID)
407  {
408    packet::ClassID *classid = new packet::ClassID();
409    classid->setPeerID(clientID);
410
411    int failures = 0;
412    while(!classid->send(static_cast<Host*>(this)) && failures < 10)\
413    {
414      failures++;
415    }
416    assert(failures<10);
417    orxout(verbose, context::network) << "syncClassid:\tall synchClassID packets have been sent" << endl;
418  }
419
420}
Note: See TracBrowser for help on using the repository browser.