Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/network/GamestateManager.cc @ 12141

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