Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/network/synchronizeable.cc @ 10766

Last change on this file since 10766 was 10114, checked in by patrick, 18 years ago

merged network back to trunk

File size: 21.9 KB
RevLine 
[5523]1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
[5547]11
[5523]12### File Specific:
[9406]13   main-programmer: Christoph Renner (rennerc@ee.ethz.ch)
14   co-programmer: Patrick Boenzli (patrick@orxonox.ethz.ch)
[5547]15*/
[5523]16
[6139]17#define DEBUG_MODULE_NETWORK
18
[6695]19#include "shared_network_data.h"
20#include "network_stream.h"
[5547]21#include "netdefs.h"
[7954]22#include "network_log.h"
[8068]23#include "network_game_manager.h"
[5529]24
[6695]25#include "state.h"
[5996]26
[6753]27#include <cassert>
[6695]28
29#include "synchronizeable.h"
30
[9406]31#include "converter.h"
[6695]32
[10114]33#include "synchronizeable_var/synchronizeable_classid.h"
[6695]34
[10114]35
[9869]36ObjectListDefinition(Synchronizeable);
[9406]37
[5547]38/**
[5807]39 *  default constructor
[5547]40 */
[5996]41Synchronizeable::Synchronizeable()
[5997]42{
[9869]43  this->registerObject(this, Synchronizeable::_objectList);
[8068]44  this->owner = 0;
[9406]45//   this->setIsServer(SharedNetworkData::getInstance()->getHostID() == 0);
[6695]46  this->uniqueID = NET_UID_UNASSIGNED;
[6145]47  this->networkStream = NULL;
[6695]48  this->bSynchronize = false;
[9406]49
[6695]50  if( State::isOnline())
51  {
52    NetworkStream* nd = SharedNetworkData::getInstance()->getDefaultSyncStream();
53    assert(nd != NULL);
54    nd->connectSynchronizeable(*this);
55    this->setUniqueID(SharedNetworkData::getInstance()->getNewUniqueID());
56  }
[7954]57
58  /* make sure loadClassId is first synced var because this is read by networkStream */
59  assert( syncVarList.size() == 0 );
[10114]60  assert( this->getClassID() == this->objectList().id() );
61 
62  mLeafClassId = this->registerVarId( new SynchronizeableClassID( this, "leafClassId", PERMISSION_MASTER_SERVER) );
[9406]63
[9656]64  this->registerVar( new SynchronizeableInt( &this->owner, &this->owner, "owner", PERMISSION_MASTER_SERVER ) );
65  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName", PERMISSION_MASTER_SERVER ) );
[5997]66}
67
[5523]68
[5996]69
[5547]70/**
[5807]71 *  default destructor deletes all unneded stuff
[5547]72 */
73Synchronizeable::~Synchronizeable()
[6139]74{
75  if ( this->networkStream )
[9110]76  {
[6139]77    this->networkStream->disconnectSynchronizeable(*this);
[9406]78
[9494]79    // remove the message manager only by the server
80    if ( (SharedNetworkData::getInstance()->isMasterServer() )
[9869]81          && this->beSynchronized() && this->getUniqueID() > 0 && !this->isA( MessageManager::staticClassID() ) )
[9110]82      NetworkGameManager::getInstance()->removeSynchronizeable( this->getUniqueID() );
83  }
[9406]84
[8623]85  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
86  {
87    delete *it;
88  }
89  syncVarList.clear();
[9406]90
[8623]91  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
92  {
93    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
94    {
95      if ( (*it2)->data )
96      {
97        delete [] (*it2)->data;
98        (*it2)->data = NULL;
99      }
100      delete *it2;
101    }
102
103  }
[9406]104
[8623]105  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
106  {
107    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
108    {
109      if ( (*it2)->data )
110      {
111        delete [] (*it2)->data;
112        (*it2)->data = NULL;
113      }
114      delete *it2;
115    }
116  }
[6139]117}
[5523]118
119
[6695]120
[5547]121/**
[9406]122 * creates a diff image from two states
123 * @param userId: the userid of the user where the image will be sent to
124 * @param data: the binary data array to write to
125 * @param maxLength: maximal length of the data written (length of available space in the array)
126 * @param stateId: the state id that this diff will represent
127 * @param priorityTH: the priority threshold: all syncs below this threshold won't be synchronized
128 *
129 * @todo check for permissions
[5547]130 */
[7954]131int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
132{
[9656]133  // make sure this user has his history or resize for new clients
134  if ( (int)sentStates.size() <= userId )
[7954]135    sentStates.resize( userId+1 );
[5547]136
[7954]137  //calculate needed memory
138  int neededSize = 0;
[5997]139
[9656]140  // calculate the needed space for network packet by summing up
[7954]141  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
[8147]142  {
143    //PRINTF(0)("SIZE = %d %s\n", (*it)->getSize(), (*it)->getName().c_str());
[7954]144    neededSize += (*it)->getSize();
[8147]145  }
[5997]146
[7954]147  if ( !( neededSize <= maxLength ) )
148  {
149    PRINTF(0)( "%d > %d\n", neededSize, maxLength );
150    assert(false);
151  }
152
153  //remove older states from history than fromStateId
154  StateHistory::iterator it = sentStates[userId].begin();
155
156  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
157    it++;
158
159  if ( it != sentStates[userId].begin() )
160  {
161    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
162    {
163      if ( (*it2)->data != NULL )
164      {
165        delete [] (*it2)->data;
166        (*it2)->data = NULL;
167      }
[9406]168
[8623]169      delete *it2;
[7954]170    }
171    sentStates[userId].erase( sentStates[userId].begin(), it );
172  }
173
174  //find state to create diff from
175  StateHistoryEntry * stateFrom = NULL;
176
177  it = sentStates[userId].begin();
178  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
179    it++;
180
181  if ( it == sentStates[userId].end() )
182  {
183    StateHistoryEntry * initialEntry = new StateHistoryEntry();
184
185    initialEntry->stateId = fromStateId;
186    initialEntry->dataLength = 0;
187    initialEntry->data = NULL;
188
189    stateFrom = initialEntry;
[9406]190
[8623]191    sentStates[userId].push_back( stateFrom );
[7954]192  }
193  else
194    stateFrom = (*it);
195
[8623]196  StateHistoryEntry * stateTo = new StateHistoryEntry;
[7954]197
[8623]198  sentStates[userId].push_back( stateTo );
[9406]199
[7954]200  stateTo->stateId = stateId;
201  stateTo->dataLength = neededSize;
202  stateTo->data = new byte[ neededSize ];
203
204  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
205
206  int i = 0;
207  int n;
[9406]208
[8623]209  bool sizeChanged = false;
[7954]210
211  // now do the actual synchronization: kick all variables to write into a common buffer
212  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
213  {
[9406]214
[9656]215    ////////////////////////////////
216    // Data SENDING Permissions
217    ////////////////////////////////
218    bool hasPermission = false;
219    bool b1, b2, b3, b4, b5, b6, b7, b8, b9;
220    b1 = b2 = b3 = b4 = b5 = b6 = b7 = b8 = b9 = false;
221
222
223    // Permission   OWNER accept if:
224    // I am the owner
225    if(       (*it)->checkPermission( PERMISSION_OWNER ) && this->owner == SharedNetworkData::getInstance()->getHostID()) {
226      hasPermission = true; b1 = true; }
227    // reciever != owner && owner is local
228    else if(  (*it)->checkPermission( PERMISSION_OWNER ) && userId != this->owner &&
229                (SharedNetworkData::getInstance()->isUserLocal(this->owner) || this->owner == SharedNetworkData::getInstance()->getHostID())) {
230      hasPermission = true; b2 = true; }
231
232
233    // Permission   MASTER_SERVER accept if:
234    // im MASTER_SERVER
235    else if( (*it)->checkPermission( PERMISSION_MASTER_SERVER ) && SharedNetworkData::getInstance()->isMasterServer()) {
236      hasPermission = true; b3 = true; }
237    // im PROXY_SERVER && reciever == CLIENT
238    else if( (*it)->checkPermission( PERMISSION_MASTER_SERVER ) && SharedNetworkData::getInstance()->isProxyServerActive() &&
239               SharedNetworkData::getInstance()->isUserClient( userId)) {
240      hasPermission = true;  b4 = true; }
241
242
243    // Pemission    SERVER accept if:
244    // i am server && reciever == CLIENT
245    else if( (*it)->checkPermission( PERMISSION_SERVER ) && !SharedNetworkData::getInstance()->isClient() &&
246               SharedNetworkData::getInstance()->isUserClient( userId)) {
247      hasPermission = true; b5 = true; }
248    // i am SERVER && reciever == SERVER && reciever != owner && ( owner is local || i am owner)
249    else if( (*it)->checkPermission( PERMISSION_SERVER ) && !SharedNetworkData::getInstance()->isClient() &&
250               userId != this->owner &&
251               ( SharedNetworkData::getInstance()->isUserLocal( this->owner) || this->owner ==  SharedNetworkData::getInstance()->getHostID())) {
252      hasPermission = true; b6 = true; }
253
254
255    // Permission   ALL accept if:
256    else if( (*it)->checkPermission( PERMISSION_ALL )) {
257      hasPermission = true; b7 = true; }
258    // or else refuse sending data
[9406]259    else
260      hasPermission = false;
261
262
[9656]263
[9406]264    if ( sizeIter == stateFrom->sizeList.end() || *sizeIter != (*it)->getSize() )
[8623]265      sizeChanged = true;
[9406]266
[8623]267    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeChanged )
[7954]268    {
269      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
270      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
[9656]271//       PRINTF(0)("sending %s %d\n", (*it)->getName().c_str(), n);
272
[10114]273//       if( this->isA( Playable::staticClassID() ))
[9656]274//       {
275//         PRINTF(0)("ms: %i, ps: %i, c: %i, sender: %i, reciever: %i, owner: %i, perm: (ow %i, ms %i, s %i, a %i)\n",
276//         SharedNetworkData::getInstance()->isMasterServer(), SharedNetworkData::getInstance()->isProxyServerActive(), SharedNetworkData::getInstance()->isClient(),
277//         SharedNetworkData::getInstance()->getHostID(), userId, this->owner,
278//         (*it)->checkPermission( PERMISSION_OWNER ), (*it)->checkPermission( PERMISSION_MASTER_SERVER ),
279//         (*it)->checkPermission( PERMISSION_SERVER ), (*it)->checkPermission( PERMISSION_ALL ));
280//         PRINTF(0)("hasPermission: %i, sizeChanged: %i, eval: %i, %i, %i, %i, %i, %i, %i\n", hasPermission, sizeChanged, b1, b2, b3, b4, b5, b6, b7);
281//         PRINTF(0)("sending %s %s %d\n", this->getClassCName(), (*it)->getName().c_str(), n);
282//       }
283
284
[7954]285      stateTo->sizeList.push_back( n );
[9406]286      // this is only for very hardcore debug sessions
287      // (*it)->debug();
[7954]288      i += n;
289    }
290    else
291    {
292      for ( int j = 0; j<(*sizeIter); j++ )
293      {
294        assert( i < stateFrom->dataLength );
295        stateTo->data[i] = stateFrom->data[i];
296        i++;
297      }
298      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
299      stateTo->sizeList.push_back( (*sizeIter) );
300    }
301
302    if ( sizeIter != stateFrom->sizeList.end() )
303      sizeIter++;
304  }
305
[8147]306  if ( i != neededSize )
307  {
[9406]308    PRINTF(0)("strange error: (%s) %d != %d\n", this->getClassCName(), i, neededSize);
[8147]309    assert(false);
310  }
[7954]311
312  //write diff to data
313  for ( i = 0; i<neededSize; i++ )
314  {
315    if ( i < stateFrom->dataLength )
316      data[i] = stateTo->data[i] - stateFrom->data[i];
317    else
318      data[i] = stateTo->data[i];
319  }
320
321  return neededSize;
322}
323
[5997]324/**
[9656]325 * sets a new state out of a diff created on another host (recieving data)
[7954]326 * @param userId hostId of user who send me that diff
327 * @param data pointer to diff
328 * @param length length of diff
329 * @param stateId id of current state
330 * @param fromStateId id of the base state id
331 * @return number bytes read
[9406]332 *
[7954]333 * @todo check for permissions
[5997]334 */
[7954]335int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
[5997]336{
[7954]337  //make sure this user has his history
[9656]338  if ( (int)recvStates.size() <= userId )
[7954]339    recvStates.resize( userId+1 );
340
341  //create new state
342  StateHistoryEntry * stateTo = new StateHistoryEntry();
343  stateTo->stateId = stateId;
344  stateTo->dataLength = length;
345  stateTo->data = new byte[ length ];
346
347
348  //find state to apply diff to
349  StateHistoryEntry * stateFrom = NULL;
350
[9406]351  // search the state from wich the diff is made of
[7954]352  StateHistory::iterator it = recvStates[userId].begin();
353  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
354    it++;
355
[9406]356  // if this is the first state to receive
[7954]357  if ( it == recvStates[userId].end() )
358  {
359    StateHistoryEntry * initialEntry = new StateHistoryEntry();
360
361    initialEntry->stateId = fromStateId;
362    initialEntry->dataLength = 0;
363    initialEntry->data = NULL;
364
365    stateFrom = initialEntry;
[9406]366
[8623]367    recvStates[userId].push_back( stateFrom );
[7954]368  }
[5997]369  else
[7954]370    stateFrom = (*it);
[9406]371
372
373  // apply diff
[7954]374  for ( int i = 0; i<length; i++ )
375  {
376    if ( i < stateFrom->dataLength )
377      stateTo->data[i] = stateFrom->data[i] + data[i];
378    else
379      stateTo->data[i] = data[i];
380  }
[9406]381
[7954]382  //add state to state history
383  recvStates[userId].push_back( stateTo );
[9406]384
[7954]385  int i = 0;
386  int n = 0;
387  std::list<int> changes;
[9406]388
389  // extract the new state for every client
[7954]390  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
391  {
[9406]392    // DATA PERMISSIONS
393    // check if this synchronizeable has the permissions to write the data
394
[9656]395    bool hasPermission = false;
396    bool b1, b2, b3, b4, b5, b6, b7, b8, b9;
397    b1 = b2 = b3 = b4 = b5 = b6 = b7 = b8 = b9 = false;
398
399    ////////////////////////////////
400    // Data RECIEVING Permissions
401    ////////////////////////////////
402
403    // i should never ever receive a state update from a synchronizeable, that belongs to me! If it does somethings wrong with the send rules
404//     assert(   !((*it)->checkPermission( PERMISSION_OWNER ) && this->owner == SharedNetworkData::getInstance()->getHostID()));
405
406
407    // Permission   OWNER accept if:
408    // sender == owner
409    if(      (*it)->checkPermission( PERMISSION_OWNER ) && this->owner == userId) {
410      hasPermission = true; b1 = true; }
411    // sender == MASTER_SERVER
412    else if( (*it)->checkPermission( PERMISSION_OWNER ) && SharedNetworkData::getInstance()->isUserMasterServer( userId)
413               && this->owner != SharedNetworkData::getInstance()->getHostID()) {
414      hasPermission = true; b2 = true; }
415    // sender == PROXY_SERVER
416      else if( (*it)->checkPermission( PERMISSION_OWNER ) && SharedNetworkData::getInstance()->isUserProxyServerActive( userId) &&
417                 this->owner != SharedNetworkData::getInstance()->getHostID()) {
418        hasPermission = true; b3 = true; }
419
420
421
422    // Permission   MASTER_SERVER accept if:
423    // sender == MASTER_SERVER
424    else if( (*it)->checkPermission( PERMISSION_MASTER_SERVER) && SharedNetworkData::getInstance()->isUserMasterServer( userId)) {
425      hasPermission = true; b4 = true; }
426    // sender == PROXY_SERVER && im not MASTER_SERVER && im not PROXY_SERVER
427    else if( (*it)->checkPermission( PERMISSION_MASTER_SERVER) && SharedNetworkData::getInstance()->isClient() &&
428               SharedNetworkData::getInstance()->isUserProxyServerActive( userId)) {
429      hasPermission = true; b5 = true; }
430
431    // Permission   SERVER accept if:
432    // sender == SERVER
433    else if( (*it)->checkPermission( PERMISSION_SERVER ) && !SharedNetworkData::getInstance()->isUserClient( userId) /*&&
434               SharedNetworkData::getInstance()->isClient()*/) {
435      hasPermission = true; b6 = true; }
436
437
438
439    // Pemission    ALL accept if:
440    else if(  (*it)->checkPermission( PERMISSION_ALL )) {
441      hasPermission = true; b8 = true; }
442
443
444   // no rights to over-write local data
[9406]445    else
446      hasPermission = false;
447
448
449
450    // if it has the permission to write do it
451    if( hasPermission)
[7954]452    {
453      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
454      i += n;
[9406]455      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
[9656]456//       PRINTF(0)("recieving: %s %d\n",  (*it)->getName().c_str(), n);
[7954]457      //(*it)->debug();
[9656]458
[10114]459//       if( this->isA(Playable::staticClassID()))
[9656]460//       {
461//         PRINTF(0)("ms: %i, ps: %i, c: %i, sender: %i, reciever: %i, owner: %i, perm: (ow %i, ms %i, s %i, a %i)\n",
462//         SharedNetworkData::getInstance()->isMasterServer(), SharedNetworkData::getInstance()->isProxyServerActive(), SharedNetworkData::getInstance()->isClient(),
463//         userId, SharedNetworkData::getInstance()->getHostID(), this->owner,
464//         (*it)->checkPermission( PERMISSION_OWNER ), (*it)->checkPermission( PERMISSION_MASTER_SERVER ),
465//         (*it)->checkPermission( PERMISSION_SERVER ), (*it)->checkPermission( PERMISSION_ALL ));
466//         PRINTF(0)("hasPermission: %i, eval: %i, %i, %i, %i, %i, %i, %i, %i\n", hasPermission, b1, b2, b3, b4, b5, b6, b7, b8);
467//         PRINTF(0)("rec %s %s %d\n", this->getClassCName(), (*it)->getName().c_str(), n);
468//       }
469
470
[7954]471      if ( (*it)->getHasChanged() )
472      {
473        changes.push_back( (*it)->getVarId() );
474      }
475    }
476    else
477    {
[9494]478//       PRINTF(0)("DONT SET VAR BECAUSE OF PERMISSION: %s perm: %d %d %d - %d %d %d\n", (*it)->getName().c_str(), (*it)->checkPermission( PERMISSION_MASTER_SERVER ), (*it)->checkPermission( PERMISSION_OWNER ), (*it)->checkPermission( PERMISSION_ALL ), networkStream->isUserMasterServer( userId ), this->owner, userId );
[7954]479      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
[9406]480      //NETPRINTF(0)("%s::setvar %s %d\n", getClassCName(), (*it)->getName().c_str(), n);
[7954]481      //(*it)->debug();
482      i += n;
483    }
484  }
485
486  this->varChangeHandler( changes );
[9406]487
[7954]488  return i;
[5997]489}
490
[7954]491 /**
492 * override this function to be notified on change
493 * of your registred variables.
494 * @param id id's which have changed
495 */
496void Synchronizeable::varChangeHandler( std::list<int> & id )
497{
498}
[6695]499
[5997]500/**
[7954]501 * registers a varable to be synchronized over network
502 * @param var see src/lib/network/synchronizeable_var/ for available classes
[5997]503 */
[7954]504void Synchronizeable::registerVar( SynchronizeableVar * var )
[5997]505{
[7954]506  syncVarList.push_back( var );
[5997]507}
508
509/**
[7954]510 * registers a varable to be synchronized over network
511 * return value is passed to varChangeHandler on change
512 * @param var see src/lib/network/synchronizeable_var/ for available classes
513 * @return handle passed to varChangeHandler on changes
[5997]514 */
[7954]515int Synchronizeable::registerVarId( SynchronizeableVar * var )
[5997]516{
[7954]517  syncVarList.push_back( var );
518  var->setWatched( true );
519  var->setVarId( syncVarList.size()-1 );
520  return syncVarList.size()-1;
[5997]521}
522
523/**
[7954]524 * removed user's states from memory
525 * @param userId user to clean
[5997]526 */
[7954]527void Synchronizeable::cleanUpUser( int userId )
[5997]528{
[9656]529  if ( (int)recvStates.size() > userId )
[7954]530  {
[8228]531    for ( std::list<StateHistoryEntry*>::iterator it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
[7954]532    {
[8228]533      if ( (*it)->data )
[8623]534      {
[8228]535        delete [] (*it)->data;
[8623]536        (*it)->data = NULL;
537      }
[9406]538
[8228]539      delete *it;
[7954]540    }
[8228]541    recvStates[userId].clear();
[7954]542  }
[9406]543
[9656]544  if ( (int)sentStates.size() > userId )
[7954]545  {
[9406]546
[8228]547    for ( std::list<StateHistoryEntry*>::iterator it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
[7954]548    {
[8228]549      if ( (*it)->data )
[8623]550      {
[8228]551        delete [] (*it)->data;
[8623]552        (*it)->data = NULL;
553      }
[9406]554
[8228]555      delete *it;
[7954]556    }
[8228]557    sentStates[userId].clear();
[7954]558  }
[5997]559}
[6139]560
[6341]561/**
[7954]562 * this function is called after recieving a state.
[9406]563 * @param userId
564 * @param stateId
565 * @param fromStateId
[6341]566 */
[7954]567void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
[6341]568{
[7954]569   //make sure this user has his history
[9656]570  if ( (int)recvStates.size() <= userId )
[7954]571    recvStates.resize( userId+1 );
[9406]572
[7954]573  //remove old states
574  StateHistory::iterator it = recvStates[userId].begin();
575
576#if 0
577  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
578    it++;
579
580  if ( it != recvStates[userId].begin() )
581  {
582    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
583    {
584      if ( (*it2)->data != NULL )
585      {
586        delete [] (*it2)->data;
587        (*it2)->data = NULL;
588      }
589    }
590    recvStates[userId].erase( recvStates[userId].begin(), it );
591  }
592#endif
593
594  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
595  {
596    if ( (*it)->stateId < fromStateId )
597    {
598      StateHistory::iterator delIt = it;
599      it ++;
[9406]600
[7954]601      if ( (*delIt)->data )
[8623]602      {
[7954]603        delete [] (*delIt)->data;
[8623]604        (*delIt)->data = NULL;
605      }
606      delete *delIt;
[7954]607      recvStates[userId].erase( delIt );
[9406]608
[7954]609      continue;
610    }
611    it++;
612  }
[9406]613
[7954]614  StateHistory::iterator fromState = recvStates[userId].end();
615  StateHistory::iterator toState = recvStates[userId].end();
[9406]616
[7954]617  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
618  {
619    if ( (*it)->stateId == stateId )
620      toState = it;
621    if ( (*it)->stateId == fromStateId )
622      fromState = it;
[9406]623
[7954]624    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
625      break;
626  }
[9406]627
[7954]628  // setStateDiff was not called and i know fromStateId
629  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
630  {
631    StateHistoryEntry * entry = new StateHistoryEntry;
[9406]632
[7954]633    entry->dataLength = (*fromState)->dataLength;
634    if ( entry->dataLength > 0 )
635    {
636      entry->data = new byte[entry->dataLength];
[9406]637
[7954]638      assert( (*fromState)->data );
639      memcpy( entry->data, (*fromState)->data, entry->dataLength );
640    }
641    else
642      entry->data = NULL;
[9406]643
[7954]644    entry->sizeList = (*fromState)->sizeList;
645    entry->stateId = stateId;
[9406]646
[7954]647    recvStates[userId].push_back(entry);
648  }
[6341]649}
[6139]650
[6341]651/**
[7954]652 * this function is called after sending a state
[9406]653 * @param userId
654 * @param stateId
655 * @param fromStateId
[6341]656 */
[7954]657void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
[6341]658{
[7954]659   //make sure this user has his history
[9656]660  if ( (int)sentStates.size() <= userId )
[7954]661    sentStates.resize( userId+1 );
662
663   //remove old states
664  StateHistory::iterator it = sentStates[userId].begin();
665
666  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
667  {
668    if ( (*it)->stateId < fromStateId )
669    {
670      StateHistory::iterator delIt = it;
671      it ++;
[9406]672
[7954]673      if ( (*delIt)->data )
[8623]674      {
[7954]675        delete [] (*delIt)->data;
[8623]676        (*delIt)->data = NULL;
677      }
678      delete *delIt;
[7954]679      sentStates[userId].erase( delIt );
[9406]680
[7954]681      continue;
682    }
683    it++;
684  }
685
[9406]686
[7954]687  StateHistory::iterator fromState = sentStates[userId].end();
688  StateHistory::iterator toState = sentStates[userId].end();
[9406]689
[7954]690  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
691  {
692    if ( (*it)->stateId == stateId )
693      toState = it;
694    if ( (*it)->stateId == fromStateId )
695      fromState = it;
[9406]696
[7954]697    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
698      break;
699  }
700
[9406]701
[7954]702  // getStateDiff was not called and i know fromStateId
703  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
704  {
705    StateHistoryEntry * entry = new StateHistoryEntry;
[9406]706
[7954]707    entry->dataLength = (*fromState)->dataLength;
708    if ( entry->dataLength > 0 )
709    {
710      entry->data = new byte[entry->dataLength];
[9406]711
[7954]712      assert( (*fromState)->data );
713      memcpy( entry->data, (*fromState)->data, entry->dataLength );
714    }
715    else
716      entry->data = NULL;
[9406]717
[7954]718    entry->sizeList = (*fromState)->sizeList;
719    entry->stateId = stateId;
[9406]720
[7954]721    sentStates[userId].push_back(entry);
722  }
[9406]723
[6341]724}
[6139]725
[6341]726
727
Note: See TracBrowser for help on using the repository browser.