Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9372 was 9371, checked in by bensch, 18 years ago

orxonox/trunk: ORXONOX is now completely std::stringed

File size: 15.5 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:
13   main-programmer: Silvan Nellen
[5997]14   co-programmer: Benjamin Wuest
[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
31
32
[5547]33/**
[5807]34 *  default constructor
[5547]35 */
[5996]36Synchronizeable::Synchronizeable()
[5997]37{
[6341]38  this->setClassID(CL_SYNCHRONIZEABLE, "Synchronizeable");
[8068]39  this->owner = 0;
[9347]40//   this->setIsServer(SharedNetworkData::getInstance()->getHostID() == 0);
[6695]41  this->uniqueID = NET_UID_UNASSIGNED;
[6145]42  this->networkStream = NULL;
[6695]43  this->bSynchronize = false;
[9347]44
[6695]45  if( State::isOnline())
46  {
47    NetworkStream* nd = SharedNetworkData::getInstance()->getDefaultSyncStream();
48    assert(nd != NULL);
49    nd->connectSynchronizeable(*this);
50    this->setUniqueID(SharedNetworkData::getInstance()->getNewUniqueID());
51  }
[7954]52
53  /* make sure loadClassId is first synced var because this is read by networkStream */
54  assert( syncVarList.size() == 0 );
55  mLeafClassId = this->registerVarId( new SynchronizeableInt( (int*)&this->getLeafClassID(), (int*)&this->getLeafClassID(), "leafClassId" ) );
[9347]56
[7954]57  this->registerVar( new SynchronizeableInt( &this->owner, &this->owner, "owner" ) );
58  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName" ) );
[5997]59}
60
[5523]61
[5996]62
[5547]63/**
[5807]64 *  default destructor deletes all unneded stuff
[5547]65 */
66Synchronizeable::~Synchronizeable()
[6139]67{
68  if ( this->networkStream )
[9110]69  {
[6139]70    this->networkStream->disconnectSynchronizeable(*this);
[9347]71
72    if ( SharedNetworkData::getInstance()->isMasterServer() && this->beSynchronized() && this->getUniqueID() > 0 && !this->isA( CL_MESSAGE_MANAGER ) )
[9110]73      NetworkGameManager::getInstance()->removeSynchronizeable( this->getUniqueID() );
74  }
[9347]75
[8623]76  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
77  {
78    delete *it;
79  }
80  syncVarList.clear();
[9347]81
[8623]82  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
83  {
84    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
85    {
86      if ( (*it2)->data )
87      {
88        delete [] (*it2)->data;
89        (*it2)->data = NULL;
90      }
91      delete *it2;
92    }
93
94  }
[9347]95
[8623]96  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
97  {
98    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
99    {
100      if ( (*it2)->data )
101      {
102        delete [] (*it2)->data;
103        (*it2)->data = NULL;
104      }
105      delete *it2;
106    }
107  }
[6139]108}
[5523]109
110
[6695]111
[7954]112int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
113{
114  //make sure this user has his history
115  if ( sentStates.size() <= userId )
116    sentStates.resize( userId+1 );
[5547]117
[7954]118  //calculate needed memory
119  int neededSize = 0;
[5997]120
[7954]121  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
[8147]122  {
123    //PRINTF(0)("SIZE = %d %s\n", (*it)->getSize(), (*it)->getName().c_str());
[7954]124    neededSize += (*it)->getSize();
[8147]125  }
[5997]126
[7954]127  if ( !( neededSize <= maxLength ) )
128  {
129    PRINTF(0)( "%d > %d\n", neededSize, maxLength );
130    assert(false);
131  }
132
133  //remove older states from history than fromStateId
134  StateHistory::iterator it = sentStates[userId].begin();
135
136  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
137    it++;
138
139  if ( it != sentStates[userId].begin() )
140  {
141    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
142    {
143      if ( (*it2)->data != NULL )
144      {
145        delete [] (*it2)->data;
146        (*it2)->data = NULL;
147      }
[9347]148
[8623]149      delete *it2;
[7954]150    }
151    sentStates[userId].erase( sentStates[userId].begin(), it );
152  }
153
154  //find state to create diff from
155  StateHistoryEntry * stateFrom = NULL;
156
157  it = sentStates[userId].begin();
158  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
159    it++;
160
161  if ( it == sentStates[userId].end() )
162  {
163    StateHistoryEntry * initialEntry = new StateHistoryEntry();
164
165    initialEntry->stateId = fromStateId;
166    initialEntry->dataLength = 0;
167    initialEntry->data = NULL;
168
169    stateFrom = initialEntry;
[9347]170
[8623]171    sentStates[userId].push_back( stateFrom );
[7954]172  }
173  else
174    stateFrom = (*it);
175
[8623]176  StateHistoryEntry * stateTo = new StateHistoryEntry;
[7954]177
[8623]178  sentStates[userId].push_back( stateTo );
[9347]179
[7954]180  stateTo->stateId = stateId;
181  stateTo->dataLength = neededSize;
182  stateTo->data = new byte[ neededSize ];
183
184  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
185
186  int i = 0;
187  int n;
[9347]188
[7954]189  bool hasPermission;
[8623]190  bool sizeChanged = false;
[7954]191
192  // now do the actual synchronization: kick all variables to write into a common buffer
193  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
194  {
195    hasPermission = (
[9347]196        SharedNetworkData::getInstance()->isMasterServer() && (*it)->checkPermission( PERMISSION_MASTER_SERVER ) ||
[8708]197        this->owner == SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ) ||
[9347]198        SharedNetworkData::getInstance()->isMasterServer() && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ) ||
199            (*it)->checkPermission( PERMISSION_ALL )
[7954]200                    );
[9347]201
202    if ( sizeIter == stateFrom->sizeList.end() || *sizeIter != (*it)->getSize() )
[8623]203      sizeChanged = true;
[9347]204
[8623]205    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeChanged )
[7954]206    {
207      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
208      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
209      stateTo->sizeList.push_back( n );
210      //(*it)->debug();
211      i += n;
212    }
213    else
214    {
215      for ( int j = 0; j<(*sizeIter); j++ )
216      {
217        assert( i < stateFrom->dataLength );
218        stateTo->data[i] = stateFrom->data[i];
219        i++;
220      }
221      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
222      stateTo->sizeList.push_back( (*sizeIter) );
223    }
224
225    if ( sizeIter != stateFrom->sizeList.end() )
226      sizeIter++;
227  }
228
[8147]229  if ( i != neededSize )
230  {
[9371]231    PRINTF(0)("strange error: (%s) %d != %d\n", this->getClassCName(), i, neededSize);
[8147]232    assert(false);
233  }
[7954]234
235  //write diff to data
236  for ( i = 0; i<neededSize; i++ )
237  {
238    if ( i < stateFrom->dataLength )
239      data[i] = stateTo->data[i] - stateFrom->data[i];
240    else
241      data[i] = stateTo->data[i];
242  }
243
244  return neededSize;
245}
246
[5997]247/**
[7954]248 * sets a new state out of a diff created on another host
249 * @param userId hostId of user who send me that diff
250 * @param data pointer to diff
251 * @param length length of diff
252 * @param stateId id of current state
253 * @param fromStateId id of the base state id
254 * @return number bytes read
255 * @todo check for permissions
[5997]256 */
[7954]257int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
[5997]258{
[7954]259  //make sure this user has his history
260  if ( recvStates.size() <= userId )
261    recvStates.resize( userId+1 );
262
263  //create new state
264  StateHistoryEntry * stateTo = new StateHistoryEntry();
265  stateTo->stateId = stateId;
266  stateTo->dataLength = length;
267  stateTo->data = new byte[ length ];
268
269
270  //find state to apply diff to
271  StateHistoryEntry * stateFrom = NULL;
272
273  StateHistory::iterator it = recvStates[userId].begin();
274  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
275    it++;
276
[9347]277
[7954]278//  if ( getLeafClassID() == CL_SPACE_SHIP )
279//  {
280//    PRINTF(0)("setStateDiff:SpaceShip from: %d stateId: %d\n", (it == recvStates[userId].end())?-1:fromStateId, stateId);
281//  }
282
283  if ( it == recvStates[userId].end() )
284  {
285    StateHistoryEntry * initialEntry = new StateHistoryEntry();
286
287    initialEntry->stateId = fromStateId;
288    initialEntry->dataLength = 0;
289    initialEntry->data = NULL;
290
291    stateFrom = initialEntry;
[9347]292
[8623]293    recvStates[userId].push_back( stateFrom );
[7954]294  }
[5997]295  else
[7954]296    stateFrom = (*it);
[9347]297
[7954]298  //apply diff
299  for ( int i = 0; i<length; i++ )
300  {
301    if ( i < stateFrom->dataLength )
302      stateTo->data[i] = stateFrom->data[i] + data[i];
303    else
304      stateTo->data[i] = data[i];
[9347]305
[7954]306  }
[9347]307
[7954]308  //add state to state history
309  recvStates[userId].push_back( stateTo );
[9347]310
[7954]311  int i = 0;
312  int n = 0;
313  std::list<int> changes;
[9347]314
[7954]315  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
316  {
317    if (
[9347]318        (*it)->checkPermission( PERMISSION_MASTER_SERVER ) && networkStream->isUserMasterServer( userId ) ||
[7954]319        (*it)->checkPermission( PERMISSION_OWNER ) && this->owner == userId ||
[9347]320        networkStream->isUserMasterServer( userId ) && this->owner != SharedNetworkData::getInstance()->getHostID() && (*it)->checkPermission( PERMISSION_OWNER ) ||
321        (*it)->checkPermission( PERMISSION_ALL )
[7954]322       )
323    {
324      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
325      i += n;
326      //NETPRINTF(0)("%s::setvar %s %d\n", getClassName(), (*it)->getName().c_str(), n);
327      //(*it)->debug();
328      if ( (*it)->getHasChanged() )
329      {
330        changes.push_back( (*it)->getVarId() );
331      }
332    }
333    else
334    {
[9347]335//      PRINTF(0)("DONT SET VAR BECAUSE OF PERMISSION: %s %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->isUserServer( userId ), this->owner, userId );
[7954]336      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
337      //NETPRINTF(0)("%s::setvar %s %d\n", getClassName(), (*it)->getName().c_str(), n);
338      //(*it)->debug();
339      i += n;
340    }
341  }
342
343  this->varChangeHandler( changes );
[9347]344
[7954]345  return i;
[5997]346}
347
[7954]348 /**
349 * override this function to be notified on change
350 * of your registred variables.
351 * @param id id's which have changed
352 */
353void Synchronizeable::varChangeHandler( std::list<int> & id )
354{
355}
[6695]356
[5997]357/**
[7954]358 * registers a varable to be synchronized over network
359 * @param var see src/lib/network/synchronizeable_var/ for available classes
[5997]360 */
[7954]361void Synchronizeable::registerVar( SynchronizeableVar * var )
[5997]362{
[8068]363  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
[7954]364  syncVarList.push_back( var );
[5997]365}
366
367/**
[7954]368 * registers a varable to be synchronized over network
369 * return value is passed to varChangeHandler on change
370 * @param var see src/lib/network/synchronizeable_var/ for available classes
371 * @return handle passed to varChangeHandler on changes
[5997]372 */
[7954]373int Synchronizeable::registerVarId( SynchronizeableVar * var )
[5997]374{
[8068]375  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
[7954]376  syncVarList.push_back( var );
377  var->setWatched( true );
378  var->setVarId( syncVarList.size()-1 );
379  return syncVarList.size()-1;
[5997]380}
381
382/**
[7954]383 * removed user's states from memory
384 * @param userId user to clean
[5997]385 */
[7954]386void Synchronizeable::cleanUpUser( int userId )
[5997]387{
[8228]388  if ( recvStates.size() > userId )
[7954]389  {
[8228]390    for ( std::list<StateHistoryEntry*>::iterator it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
[7954]391    {
[8228]392      if ( (*it)->data )
[8623]393      {
[8228]394        delete [] (*it)->data;
[8623]395        (*it)->data = NULL;
396      }
[9347]397
[8228]398      delete *it;
[7954]399    }
[8228]400    recvStates[userId].clear();
[7954]401  }
[9347]402
[8228]403  if ( sentStates.size() > userId )
[7954]404  {
[9347]405
[8228]406    for ( std::list<StateHistoryEntry*>::iterator it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
[7954]407    {
[8228]408      if ( (*it)->data )
[8623]409      {
[8228]410        delete [] (*it)->data;
[8623]411        (*it)->data = NULL;
412      }
[9347]413
[8228]414      delete *it;
[7954]415    }
[8228]416    sentStates[userId].clear();
[7954]417  }
[5997]418}
[6139]419
[6341]420/**
[7954]421 * this function is called after recieving a state.
[9347]422 * @param userId
423 * @param stateId
424 * @param fromStateId
[6341]425 */
[7954]426void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
[6341]427{
[7954]428   //make sure this user has his history
429  if ( recvStates.size() <= userId )
430    recvStates.resize( userId+1 );
[9347]431
[7954]432  //remove old states
433  StateHistory::iterator it = recvStates[userId].begin();
434
435#if 0
436  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
437    it++;
438
439  if ( it != recvStates[userId].begin() )
440  {
441    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
442    {
443      if ( (*it2)->data != NULL )
444      {
445        delete [] (*it2)->data;
446        (*it2)->data = NULL;
447      }
448    }
449    recvStates[userId].erase( recvStates[userId].begin(), it );
450  }
451#endif
452
453  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
454  {
455    if ( (*it)->stateId < fromStateId )
456    {
457      StateHistory::iterator delIt = it;
458      it ++;
[9347]459
[7954]460      if ( (*delIt)->data )
[8623]461      {
[7954]462        delete [] (*delIt)->data;
[8623]463        (*delIt)->data = NULL;
464      }
465      delete *delIt;
[7954]466      recvStates[userId].erase( delIt );
[9347]467
[7954]468      continue;
469    }
470    it++;
471  }
[9347]472
[7954]473  StateHistory::iterator fromState = recvStates[userId].end();
474  StateHistory::iterator toState = recvStates[userId].end();
[9347]475
[7954]476  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
477  {
478    if ( (*it)->stateId == stateId )
479      toState = it;
480    if ( (*it)->stateId == fromStateId )
481      fromState = it;
[9347]482
[7954]483    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
484      break;
485  }
[9347]486
[7954]487  // setStateDiff was not called and i know fromStateId
488  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
489  {
490    StateHistoryEntry * entry = new StateHistoryEntry;
[9347]491
[7954]492    entry->dataLength = (*fromState)->dataLength;
493    if ( entry->dataLength > 0 )
494    {
495      entry->data = new byte[entry->dataLength];
[9347]496
[7954]497      assert( (*fromState)->data );
498      memcpy( entry->data, (*fromState)->data, entry->dataLength );
499    }
500    else
501      entry->data = NULL;
[9347]502
[7954]503    entry->sizeList = (*fromState)->sizeList;
504    entry->stateId = stateId;
[9347]505
[7954]506    recvStates[userId].push_back(entry);
507  }
[6341]508}
[6139]509
[6341]510/**
[7954]511 * this function is called after sending a state
[9347]512 * @param userId
513 * @param stateId
514 * @param fromStateId
[6341]515 */
[7954]516void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
[6341]517{
[7954]518   //make sure this user has his history
519  if ( sentStates.size() <= userId )
520    sentStates.resize( userId+1 );
521
522   //remove old states
523  StateHistory::iterator it = sentStates[userId].begin();
524
525  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
526  {
527    if ( (*it)->stateId < fromStateId )
528    {
529      StateHistory::iterator delIt = it;
530      it ++;
[9347]531
[7954]532      if ( (*delIt)->data )
[8623]533      {
[7954]534        delete [] (*delIt)->data;
[8623]535        (*delIt)->data = NULL;
536      }
537      delete *delIt;
[7954]538      sentStates[userId].erase( delIt );
[9347]539
[7954]540      continue;
541    }
542    it++;
543  }
544
[9347]545
[7954]546  StateHistory::iterator fromState = sentStates[userId].end();
547  StateHistory::iterator toState = sentStates[userId].end();
[9347]548
[7954]549  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
550  {
551    if ( (*it)->stateId == stateId )
552      toState = it;
553    if ( (*it)->stateId == fromStateId )
554      fromState = it;
[9347]555
[7954]556    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
557      break;
558  }
559
[9347]560
[7954]561  // getStateDiff was not called and i know fromStateId
562  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
563  {
564    StateHistoryEntry * entry = new StateHistoryEntry;
[9347]565
[7954]566    entry->dataLength = (*fromState)->dataLength;
567    if ( entry->dataLength > 0 )
568    {
569      entry->data = new byte[entry->dataLength];
[9347]570
[7954]571      assert( (*fromState)->data );
572      memcpy( entry->data, (*fromState)->data, entry->dataLength );
573    }
574    else
575      entry->data = NULL;
[9347]576
[7954]577    entry->sizeList = (*fromState)->sizeList;
578    entry->stateId = stateId;
[9347]579
[7954]580    sentStates[userId].push_back(entry);
581  }
[9347]582
[6341]583}
[6139]584
[6341]585
586
Note: See TracBrowser for help on using the repository browser.