Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

some more smaller works:

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