Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/proxy/src/lib/network/synchronizeable.cc @ 9635

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

the other SERVER doesn't check anymore if the variable was sent correctly

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