Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/network/GamestateManager.cc @ 9001

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

Replaced COUT with orxout in network library. Tried to set levels and contexts in a more or less useful way, but not really optimized. Used contexts network, packets, and master_server.
Please use endl instead of \n in the future (@smerkli) ;)

  • Property svn:eol-style set to native
File size: 12.7 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// #include <boost/thread/mutex.hpp>
46
47#include "packet/Acknowledgement.h"
48#include "packet/Gamestate.h"
49#include "synchronisable/NetworkCallbackManager.h"
50
51#include "core/ThreadPool.h"
52#include "core/command/Executor.h"
53#include "core/GameMode.h"
54#include "util/Output.h"
55#include "util/Clock.h"
56#include "util/OrxAssert.h"
57// #include "TrafficControl.h"
58
59namespace orxonox
60{ 
61  GamestateManager::GamestateManager() :
62  currentGamestate_(0), id_(0)
63  {
64//     trafficControl_ = new TrafficControl();
65//     threadMutex_ = new boost::mutex();
66//     threadPool_ = new ThreadPool();
67  }
68
69  GamestateManager::~GamestateManager()
70  {
71    if( this->currentGamestate_ )
72        delete this->currentGamestate_;std::map<unsigned int, packet::Gamestate*>::iterator it;
73    for( it = gamestateQueue.begin(); it != gamestateQueue.end(); ++it )
74      delete it->second;
75    std::map<uint32_t, peerInfo>::iterator peerIt;
76    std::map<uint32_t, packet::Gamestate*>::iterator gamestateIt;
77    for( peerIt = peerMap_.begin(); peerIt != peerMap_.end(); ++peerIt )
78    {
79      for( gamestateIt = peerIt->second.gamestates.begin(); gamestateIt != peerIt->second.gamestates.end(); ++gamestateIt )
80        delete gamestateIt->second;
81    }
82//     this->trafficControl_->destroy();
83//     delete this->threadMutex_;
84//     delete this->threadPool_;
85  }
86
87  bool GamestateManager::update(){
88//     cleanup();
89    return getSnapshot();
90  }
91
92  bool GamestateManager::addGamestate(packet::Gamestate *gs, unsigned int clientID)
93  {
94    assert(gs);
95    std::map<unsigned int, packet::Gamestate*>::iterator it = gamestateQueue.find(clientID);
96    if(it!=gamestateQueue.end())
97    {
98      // delete obsolete gamestate
99      delete it->second;
100    }
101    gamestateQueue[clientID] = gs;
102    return true;
103  }
104
105  bool GamestateManager::processGamestates()
106  {
107    if( this->gamestateQueue.empty() )
108        return true;
109    std::map<unsigned int, packet::Gamestate*>::iterator it;
110    // now push only the most recent gamestates we received (ignore obsolete ones)
111    for(it = gamestateQueue.begin(); it!=gamestateQueue.end(); it++)
112    {
113      OrxVerify(processGamestate(it->second), "ERROR: could not process Gamestate");
114      sendAck( it->second->getID(), it->second->getPeerID() );
115      delete it->second;
116    }
117    // now clear the queue
118    gamestateQueue.clear();
119    //and call all queued callbacks
120    NetworkCallbackManager::callCallbacks();
121    return true;
122  }
123 
124  bool GamestateManager::sendAck(unsigned int gamestateID, uint32_t peerID)
125  {
126    assert( gamestateID != ACKID_NACK );
127    packet::Acknowledgement *ack = new packet::Acknowledgement(gamestateID, peerID);
128    if( !this->sendPacket(ack))
129    {
130      orxout(internal_warning, context::network) << "could not ack gamestate: " << gamestateID << endl;
131      return false;
132    }
133    else
134    {
135      orxout(verbose_more, context::network) << "acked a gamestate: " << gamestateID << endl;
136      return true;
137    }
138  }
139
140
141  bool GamestateManager::getSnapshot(){
142    if ( currentGamestate_ != 0 )
143      delete currentGamestate_;
144    uint8_t gsMode;
145    if( GameMode::isMaster() )
146      gsMode = packet::GAMESTATE_MODE_SERVER;
147    else
148      gsMode = packet::GAMESTATE_MODE_CLIENT;
149    uint32_t newID;
150    if( GameMode::isMaster() )
151      newID = ++id_;
152    else
153    {
154      assert(peerMap_.size()!=0);
155      newID = peerMap_[NETWORK_PEER_ID_SERVER].lastReceivedGamestateID;
156      if( newID == GAMESTATEID_INITIAL )
157      {
158        return false;
159      }
160    }
161   
162    currentGamestate_ = new packet::Gamestate();
163   
164    if(!currentGamestate_->collectData(newID, gsMode))
165    { //we have no data to send
166      delete currentGamestate_;
167      currentGamestate_=0;
168      return false;
169    }
170    return true;
171  }
172
173  std::vector<packet::Gamestate*> GamestateManager::getGamestates()
174  {
175    if(!currentGamestate_)
176      return std::vector<packet::Gamestate*>();
177    std::vector<packet::Gamestate*> peerGamestates;
178   
179    std::map<uint32_t, peerInfo>::iterator peerIt;
180    for( peerIt=peerMap_.begin(); peerIt!=peerMap_.end(); ++peerIt )
181    {
182      if( !peerIt->second.isSynched )
183      {
184        orxout(verbose_more, context::network) << "Server: not sending gamestate" << endl;
185        continue;
186      }
187      orxout(verbose_more, context::network) << "client id: " << peerIt->first << endl;
188      orxout(verbose_more, context::network) << "Server: doing gamestate gamestate preparation" << endl;
189      int peerID = peerIt->first; //get client id
190
191      unsigned int lastAckedGamestateID = peerIt->second.lastAckedGamestateID;
192
193      packet::Gamestate* baseGamestate=0;
194      if(lastAckedGamestateID != GAMESTATEID_INITIAL)
195      {
196        assert(peerMap_.find(peerID)!=peerMap_.end());
197        std::map<uint32_t, packet::Gamestate*>::iterator it = peerMap_[peerID].gamestates.find(lastAckedGamestateID);
198        assert(it!=peerMap_[peerID].gamestates.end());
199        baseGamestate = it->second;
200      }
201
202      peerGamestates.push_back(0);  // insert an empty gamestate* to be changed
203      finishGamestate( peerID, peerGamestates.back(), baseGamestate, currentGamestate_ );
204      if( peerGamestates.back()==0 )
205        // nothing to send to remove pointer from vector
206        peerGamestates.pop_back();
207      //FunctorMember<GamestateManager>* functor =
208//       ExecutorMember<GamestateManager>* executor = createExecutor( createFunctor(&GamestateManager::finishGamestate, this) );
209//       executor->setDefaultValues( cid, &clientGamestates.back(), client, currentGamestate_ );
210//       (*static_cast<Executor*>(executor))();
211//       this->threadPool_->passFunction( executor, true );
212//       (*functor)( cid, &(clientGamestates.back()), client, currentGamestate_ );
213    }
214
215//     threadPool_->synchronise();
216
217    return peerGamestates;
218  }
219
220
221  void GamestateManager::finishGamestate( unsigned int peerID, packet::Gamestate*& destgamestate, packet::Gamestate* base, packet::Gamestate* gamestate ) {
222    //why are we searching the same client's gamestate id as we searched in
223    //Server::sendGameState?
224    // save the (undiffed) gamestate in the clients gamestate map
225    //chose wheather the next gamestate is the first or not
226
227//     packet::Gamestate *gs = gamestate->doSelection(clientID, 20000);
228//       packet::Gamestate* gs = new packet::Gamestate(*gamestate);
229//     packet::Gamestate* gs = gamestate;
230    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
231//     packet::Gamestate *gs = new packet::Gamestate();
232//     gs->collectData( id_, 0x1 );
233//     this->threadMutex_->lock();
234    peerMap_[peerID].gamestates[gamestate->getID()]=gs;
235//     this->threadMutex_->unlock();
236    Clock clock;
237    clock.capture();
238
239    if(base)
240    {
241      packet::Gamestate *diffed1 = gs->diffVariables(base);
242      if( diffed1->getDataSize() == 0 )
243      {
244        delete diffed1;
245        destgamestate = 0;
246        return;
247      }
248      gs = diffed1;
249    }
250    else
251    {
252      gs = new packet::Gamestate(*gs);
253    }
254
255
256//     OrxVerify(gs->compressData(), "");
257    clock.capture();
258    orxout(verbose_more, context::network) << "diff and compress time: " << clock.getDeltaTime() << endl;
259//     orxout(verbose_more, context::network) << "sending gamestate with id " << gs->getID();
260//     if(gamestate->isDiffed())
261//       orxout(verbose_more, context::network) << " and baseid " << gs->getBaseID() << endl;
262//     else
263//       orxout(verbose_more, context::network) << endl;
264    gs->setPeerID(peerID);
265    destgamestate = gs;
266  }
267
268
269  bool GamestateManager::ackGamestate(unsigned int gamestateID, unsigned int peerID)
270  {
271//     ClientInformation *temp = ClientInformation::findClient(peerID);
272//     assert(temp);
273    std::map<uint32_t, peerInfo>::iterator it = this->peerMap_.find(peerID);
274    assert(it!=this->peerMap_.end());
275    unsigned int curid = it->second.lastAckedGamestateID;
276
277    assert(gamestateID != ACKID_NACK);
278//     if(gamestateID == ACKID_NACK){
279//       it->second.lastAckedGamestateID = GAMESTATEID_INITIAL;
280// //       temp->setGamestateID(GAMESTATEID_INITIAL);
281//       // now delete all saved gamestates for this client
282//       std::map<uint32_t, packet::Gamestate*>::iterator it2;
283//       for(it2 = it->second.gamestates.begin(); it2!=it->second.gamestates.end(); ++it2 ){
284//         delete it2->second;
285//       }
286//       it->second.gamestates.clear();
287//       return true;
288//     }
289
290//    assert(curid==GAMESTATEID_INITIAL || curid<=gamestateID); // this line is commented out because acknowledgements are unreliable and may arrive in distorted order
291    if( gamestateID <= curid && curid != GAMESTATEID_INITIAL )
292        return true;
293orxout(verbose, context::network) << "acking gamestate " << gamestateID << " for peerID: " << peerID << " curid: " << curid << endl;
294    std::map<uint32_t, packet::Gamestate*>::iterator it2;
295    for( it2=it->second.gamestates.begin(); it2!=it->second.gamestates.end(); )
296    {
297      if( it2->second->getID() < gamestateID )
298      {
299        delete it2->second;
300        it->second.gamestates.erase(it2++);
301      }
302      else
303        ++it2;
304    }
305   
306//     std::map<unsigned int, packet::Gamestate*>::iterator it;
307//     for(it = gamestateMap_[peerID].begin(); it!=gamestateMap_[peerID].end() && it->first<gamestateID; ){
308//       delete it->second;
309//       gamestateMap_[peerID].erase(it++);
310//     }
311    it->second.lastAckedGamestateID = gamestateID;
312//     temp->setGamestateID(gamestateID);
313//     TrafficControl::processAck(peerID, gamestateID);
314    return true;
315  }
316 
317  uint32_t GamestateManager::getLastReceivedGamestateID(unsigned int peerID)
318  {
319    assert( this->peerMap_.find(peerID)!=this->peerMap_.end() );
320    if( this->peerMap_.find(peerID) != this->peerMap_.end() )
321      return this->peerMap_[peerID].lastReceivedGamestateID;
322    else
323      return GAMESTATEID_INITIAL;
324  }
325 
326 
327  void GamestateManager::addPeer(uint32_t peerID)
328  {
329    assert(peerMap_.find(peerID)==peerMap_.end());
330    peerMap_[peerID].peerID = peerID;
331    peerMap_[peerID].lastReceivedGamestateID = GAMESTATEID_INITIAL;
332    peerMap_[peerID].lastAckedGamestateID = GAMESTATEID_INITIAL;
333    if( GameMode::isMaster() )
334      peerMap_[peerID].isSynched = false;
335    else
336      peerMap_[peerID].isSynched = true;
337  }
338
339  void GamestateManager::removePeer(uint32_t peerID)
340  {
341    assert(peerMap_.find(peerID)!=peerMap_.end());
342    std::map<uint32_t, packet::Gamestate*>::iterator peerIt;
343    for( peerIt = peerMap_[peerID].gamestates.begin(); peerIt!=peerMap_[peerID].gamestates.end(); ++peerIt )
344    {
345      delete peerIt->second;
346    }
347    peerMap_.erase(peerMap_.find(peerID));
348  }
349
350
351//   void GamestateManager::removeClient(ClientInformation* client){
352//     assert(client);
353//     std::map<unsigned int, std::map<unsigned int, packet::Gamestate*> >::iterator clientMap = gamestateMap_.find(client->getID());
354//     // first delete all remained gamestates
355//     std::map<unsigned int, packet::Gamestate*>::iterator it;
356//     for(it=clientMap->second.begin(); it!=clientMap->second.end(); it++)
357//       delete it->second;
358//     // now delete the clients gamestatemap
359//     gamestateMap_.erase(clientMap);
360//   }
361
362  bool GamestateManager::processGamestate(packet::Gamestate *gs)
363  {
364    if(gs->isCompressed())
365    {
366       OrxVerify(gs->decompressData(), "ERROR: could not decompress Gamestate");
367    }
368    assert(!gs->isDiffed());
369    uint8_t gsMode;
370    if( GameMode::isMaster() )
371      gsMode = packet::GAMESTATE_MODE_SERVER;
372    else
373      gsMode = packet::GAMESTATE_MODE_CLIENT;
374    if( gs->spreadData(gsMode) )
375    {
376      this->peerMap_[gs->getPeerID()].lastReceivedGamestateID = gs->getID();
377      return true;
378    }
379    else
380      return false;
381  }
382
383}
Note: See TracBrowser for help on using the repository browser.