Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/PresentationFS18/src/libraries/network/GamestateManager.cc @ 12020

Last change on this file since 12020 was 12020, checked in by patricwi, 6 years ago

Merged Masterserver

  • Property svn:eol-style set to native
File size: 11.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: GameStateManager
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 "GamestateManager.h"
42
43#include <cassert>
44#include <queue>
45
46#include "packet/Acknowledgement.h"
47#include "packet/Gamestate.h"
48#include "synchronisable/NetworkCallbackManager.h"
49
50#include "core/ThreadPool.h"
51#include "core/command/Executor.h"
52#include "core/GameMode.h"
53#include "util/Output.h"
54#include "util/Clock.h"
55#include "util/OrxAssert.h"
56
57namespace orxonox
58{ 
59  GamestateManager::GamestateManager() :
60  currentGamestate_(nullptr), id_(0)
61  {
62  }
63
64  GamestateManager::~GamestateManager()
65  {
66    if(this->currentGamestate_)
67    {
68      delete this->currentGamestate_;
69      this->currentGamestate_ = nullptr;
70    }
71
72    for(const auto& gsPair : this->gamestateQueue)
73    {
74      delete gsPair.second;
75    }
76
77    for(const auto& peerPair : this->peerMap_)
78    {
79      for(const auto& gsPair : peerPair.second.gamestates)
80      {
81        delete gsPair.second;
82      }
83    }
84  }
85
86  bool GamestateManager::update()
87  {
88    return this->getSnapshot();
89  }
90
91  bool GamestateManager::addGamestate(packet::Gamestate *gs, unsigned int clientID)
92  {
93    assert(gs);
94    // Search the queue for a gamestate for the client
95    std::map<unsigned int, packet::Gamestate*>::iterator it = this->gamestateQueue.find(clientID);
96    if(it != this->gamestateQueue.end())
97    {
98      // delete obsolete gamestate
99      delete it->second;
100    }
101    // update the client's gamestate
102    this->gamestateQueue[clientID] = gs;
103
104    return true;
105  }
106
107  /**
108   * Process the queued gamestates.
109   */
110  bool GamestateManager::processGamestates()
111  {
112    // Queue is empty, nothing to do
113    if(this->gamestateQueue.empty())
114    {
115        return true;
116    }
117
118    // now push only the most recent gamestates we received (ignore obsolete ones)
119    for(const auto& gsPair : this->gamestateQueue)
120    {
121      OrxVerify(this->processGamestate(gsPair.second), "ERROR: could not process Gamestate");
122      this->sendAck(gsPair.second->getID(), gsPair.second->getPeerID());
123      delete gsPair.second;
124    }
125    // now clear the queue
126    this->gamestateQueue.clear();
127
128    //and call all queued callbacks
129    NetworkCallbackManager::callCallbacks();
130
131    return true;
132  }
133 
134  /**
135   * Send Acknowledgement packet.
136   * @param gamestateId The gamestate ID we want to acknowledge
137   * @param peerID The ID of the peer we want to send the Acknowledgement to
138   */
139  bool GamestateManager::sendAck(unsigned int gamestateID, uint32_t peerID)
140  {
141    assert(gamestateID != ACKID_NACK);
142    packet::Acknowledgement *ack = new packet::Acknowledgement(gamestateID, peerID);
143    if(!this->sendPacket(ack))
144    {
145      orxout(internal_warning, context::network) << "could not ack gamestate: " << gamestateID << endl;
146      return false;
147    }
148    else
149    {
150      orxout(verbose_more, context::network) << "acked a gamestate: " << gamestateID << endl;
151      return true;
152    }
153  }
154
155  /**
156   * Update the current gamestate.
157   */
158  bool GamestateManager::getSnapshot()
159  {
160    // Delete current gamestate
161    if (this->currentGamestate_)
162    {
163      delete this->currentGamestate_;
164      this->currentGamestate_ = nullptr;
165    }
166
167    uint8_t gsMode;
168    if(GameMode::isMaster())
169    {
170      gsMode = packet::GAMESTATE_MODE_SERVER;
171    }
172    else
173    {
174      gsMode = packet::GAMESTATE_MODE_CLIENT;
175    }
176
177    uint32_t newID;
178    if(GameMode::isMaster())
179    {
180      newID = ++this->id_;
181    }
182    else
183    {
184      assert(this->peerMap_.size() != 0);
185      newID = this->peerMap_[NETWORK_PEER_ID_SERVER].lastReceivedGamestateID;
186      if(newID == GAMESTATEID_INITIAL)
187      {
188        return false;
189      }
190    }
191   
192    // Create a new gamestate
193    this->currentGamestate_ = new packet::Gamestate();
194    if(!this->currentGamestate_->collectData(newID, gsMode))
195    {
196      // we have no data to send
197      delete this->currentGamestate_;
198      this->currentGamestate_ = nullptr;
199      return false;
200    }
201
202    return true;
203  }
204
205  /**
206   * Return a vector with the gamestates of all peers.
207   */
208  std::vector<packet::Gamestate*> GamestateManager::getGamestates()
209  {
210    // Current gamestate is empty
211    if(!this->currentGamestate_){
212      return std::vector<packet::Gamestate*>();
213    }
214
215    std::vector<packet::Gamestate*> peerGamestates;
216    for(const auto& mapEntry : this->peerMap_)
217    {
218      if(!mapEntry.second.isSynched)
219      {
220        orxout(verbose_more, context::network) << "Server: not sending gamestate" << endl;
221        continue;
222      }
223      orxout(verbose_more, context::network) << "client id: " << mapEntry.first << endl;
224      orxout(verbose_more, context::network) << "Server: doing gamestate gamestate preparation" << endl;
225      int peerID = mapEntry.first; //get client id
226
227      unsigned int lastAckedGamestateID = mapEntry.second.lastAckedGamestateID;
228
229      packet::Gamestate* baseGamestate=nullptr;
230      if(lastAckedGamestateID != GAMESTATEID_INITIAL)
231      {
232        assert(peerMap_.find(peerID)!=peerMap_.end());
233        std::map<uint32_t, packet::Gamestate*>::iterator it = peerMap_[peerID].gamestates.find(lastAckedGamestateID);
234        assert(it!=peerMap_[peerID].gamestates.end());
235        baseGamestate = it->second;
236      }
237
238      peerGamestates.push_back(nullptr);  // insert an empty gamestate* to be changed
239      finishGamestate( peerID, peerGamestates.back(), baseGamestate, currentGamestate_ );
240      if(peerGamestates.back() == nullptr)
241      {
242        // nothing to send to remove pointer from vector
243        peerGamestates.pop_back();
244      }
245    }
246
247    return peerGamestates;
248  }
249
250
251  void GamestateManager::finishGamestate(unsigned int peerID, packet::Gamestate*& destgamestate, packet::Gamestate* base, packet::Gamestate* gamestate)
252  {
253    // save the (undiffed) gamestate in the clients gamestate map
254    // choose whether the next gamestate is the first or not
255
256    // Create a copy of the gamestate
257    packet::Gamestate *gs = new packet::Gamestate(*gamestate); //this is neccessary because the gamestate are being kept (to diff them later on) for each client seperately
258    this->peerMap_[peerID].gamestates[gamestate->getID()] = gs;
259
260    // Start the clock
261    Clock clock;
262    clock.capture();
263
264    if(base)
265    {
266      packet::Gamestate *diffed1 = gs->diffVariables(base);
267      if(diffed1->getDataSize() == 0)
268      {
269        delete diffed1;
270        destgamestate = nullptr;
271        return;
272      }
273      gs = diffed1;
274    }
275    else
276    {
277      gs = new packet::Gamestate(*gs);
278    }
279
280    // Stop the clock
281    clock.capture();
282    orxout(verbose_more, context::network) << "diff and compress time: " << clock.getDeltaTime() << endl;
283
284
285    gs->setPeerID(peerID);
286    destgamestate = gs;
287  }
288
289
290  /**
291   * Acknowledge a received gamestate.
292   * @param gamestateID The ID of the gamestate to be acknowledged
293   * @param peerID The ID of the peer to send the Acknowledgement to
294   */
295  bool GamestateManager::ackGamestate(unsigned int gamestateID, unsigned int peerID)
296  {
297    // Search for the peer in the peer map
298    std::map<uint32_t, peerInfo>::iterator it = this->peerMap_.find(peerID);
299    assert(it != this->peerMap_.end());
300
301    unsigned int curid = it->second.lastAckedGamestateID;
302
303    assert(gamestateID != ACKID_NACK);
304
305    // The gamestate has already been acknowledged, nothing to do
306    if(gamestateID <= curid && curid != GAMESTATEID_INITIAL)
307    {
308        return true;
309    }
310
311    orxout(verbose, context::network) << "acking gamestate " << gamestateID << " for peerID: " << peerID << " curid: " << curid << endl;
312    std::map<uint32_t, packet::Gamestate*>::iterator it2;
313    for (it2 = it->second.gamestates.begin(); it2 != it->second.gamestates.end();)
314    {
315      if(it2->second->getID() < gamestateID)
316      {
317        delete it2->second;
318        it->second.gamestates.erase(it2++);
319      }
320      else
321      {
322        ++it2;
323      }
324    }
325   
326    // update the last acked gamestate
327    it->second.lastAckedGamestateID = gamestateID;
328
329    return true;
330  }
331 
332  /**
333   * Return the ID of the last received gamestate for a certain peer
334   * @param peerID The ID of the peer\
335   */
336  uint32_t GamestateManager::getLastReceivedGamestateID(unsigned int peerID)
337  {
338    if(this->peerMap_.find(peerID) != this->peerMap_.end())
339    {
340      return this->peerMap_[peerID].lastReceivedGamestateID;
341    }
342    else
343    {
344      return GAMESTATEID_INITIAL;
345    }
346  }
347 
348  /**
349   * Add a peer to the game.
350   * @param peerID The ID of the peer to add.
351   */
352  void GamestateManager::addPeer(uint32_t peerID)
353  {
354    // Ensure that the peer doesn't already exist.
355    assert(this->peerMap_.find(peerID) == this->peerMap_.end());
356
357    // Create the peerInfo struct for the peer
358    this->peerMap_[peerID].peerID = peerID;
359    this->peerMap_[peerID].lastReceivedGamestateID = GAMESTATEID_INITIAL;
360    this->peerMap_[peerID].lastAckedGamestateID = GAMESTATEID_INITIAL;
361    if(GameMode::isMaster())
362    {
363      this->peerMap_[peerID].isSynched = false;
364    }
365    else
366    {
367      this->peerMap_[peerID].isSynched = true;
368    }
369  }
370
371  /**
372   * Remove a peer from the game.
373   * @param peerID The ID of the peer to be removed
374   */
375  void GamestateManager::removePeer(uint32_t peerID)
376  {
377    // Make sure that the peer exists
378    assert(this->peerMap_.find(peerID) != this->peerMap_.end());
379
380    for (const auto& mapEntry : this->peerMap_[peerID].gamestates)
381    {
382      delete mapEntry.second;
383    }
384    this->peerMap_.erase(this->peerMap_.find(peerID));
385  }
386
387  /**
388   * Process an incoming Gamestate packet.
389   * @param gs Pointer to the incoming Gamestate packet
390   */
391  bool GamestateManager::processGamestate(packet::Gamestate *gs)
392  {
393    // Decompress if necessary
394    if(gs->isCompressed())
395    {
396       OrxVerify(gs->decompressData(), "ERROR: could not decompress Gamestate");
397    }
398    assert(!gs->isDiffed());
399
400    uint8_t gsMode;
401    if(GameMode::isMaster())
402    {
403      gsMode = packet::GAMESTATE_MODE_SERVER;
404    }
405    else
406    {
407      gsMode = packet::GAMESTATE_MODE_CLIENT;
408    }
409
410    if(gs->spreadData(gsMode))
411    {
412      this->peerMap_[gs->getPeerID()].lastReceivedGamestateID = gs->getID();
413      return true;
414    }
415    else
416    {
417      return false;
418    }
419  }
420
421}
Note: See TracBrowser for help on using the repository browser.