Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7731 was 7731, checked in by rennerc, 18 years ago

fixed bug

File size: 10.1 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"
[5529]22
[6695]23#include "state.h"
[5996]24
[6753]25#include <cassert>
[6695]26
27#include "synchronizeable.h"
28
29
30
[5547]31/**
[5807]32 *  default constructor
[5547]33 */
[5996]34Synchronizeable::Synchronizeable()
[5997]35{
[6341]36  this->setClassID(CL_SYNCHRONIZEABLE, "Synchronizeable");
[6753]37  this->owner = -1;
[6695]38  this->hostID = SharedNetworkData::getInstance()->getHostID();
[6341]39  this->setIsServer(this->hostID == 0);
[6695]40  this->uniqueID = NET_UID_UNASSIGNED;
[6145]41  this->networkStream = NULL;
[6695]42  this->bSynchronize = false;
[7575]43 
[6695]44  if( State::isOnline())
45  {
46    NetworkStream* nd = SharedNetworkData::getInstance()->getDefaultSyncStream();
47    assert(nd != NULL);
48    nd->connectSynchronizeable(*this);
49    this->setUniqueID(SharedNetworkData::getInstance()->getNewUniqueID());
50  }
[7512]51
[7565]52  /* make sure loadClassId is first synced var because this is read by networkStream */
53  assert( syncVarList.size() == 0 );
[7602]54  mLeafClassId = this->registerVarId( new SynchronizeableInt( (int*)&this->getLeafClassID(), (int*)&this->getLeafClassID(), "leafClassId" ) );
[7575]55   
[7565]56  this->registerVar( new SynchronizeableInt( &this->owner, &this->owner, "owner" ) );
[7444]57  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName" ) );
[5997]58}
59
[5523]60
[5996]61
[5547]62/**
[5807]63 *  default destructor deletes all unneded stuff
[5547]64 */
65Synchronizeable::~Synchronizeable()
[6139]66{
67  if ( this->networkStream )
68    this->networkStream->disconnectSynchronizeable(*this);
69}
[5523]70
[5547]71/**
[5997]72 * Sets the server flag to a given value
73 * @param isServer: the boolean value which the server flag is to set to
74 */
75void Synchronizeable::setIsServer(bool isServer)
76{
77  if( isServer )
78    this->state = this->state | STATE_SERVER;
79  else
80    this->state = this->state & (~STATE_SERVER);
81}
82
[6695]83
[5997]84/**
[7444]85 * Determines if the server flag is set
86 * @return true, if the server flag is true, false else
[5997]87 */
[7444]88bool Synchronizeable::isServer()
[5997]89{
[7444]90  return (this->state & STATE_SERVER) >0;
[5997]91}
92
[6695]93
[7631]94
[7508]95int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
[5997]96{
[7508]97  //make sure this user has his history
98  if ( sentStates.size() <= userId )
99    sentStates.resize( userId+1 );
[7512]100
[7508]101  //calculate needed memory
102  int neededSize = 0;
[7512]103
[7508]104  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
105    neededSize += (*it)->getSize();
[7512]106
[7631]107  if ( !( neededSize <= maxLength ) )
108  {
109    PRINTF(0)( "%d > %d\n", neededSize, maxLength );
110    assert(false);
111  }
[7512]112
[7508]113  //remove older states from history than fromStateId
114  StateHistory::iterator it = sentStates[userId].begin();
[7512]115
[7508]116  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
117    it++;
[7591]118
119  if ( it != sentStates[userId].begin() )
[7508]120  {
121    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
122    {
123      if ( (*it2)->data != NULL )
124      {
[7731]125        delete [] (*it2)->data;
[7508]126        (*it2)->data = NULL;
127      }
128    }
129    sentStates[userId].erase( sentStates[userId].begin(), it );
130  }
[7512]131
[7508]132  //find state to create diff from
133  StateHistoryEntry * stateFrom = NULL;
[7512]134
[7508]135  it = sentStates[userId].begin();
136  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
137    it++;
[7512]138
[7508]139  if ( it == sentStates[userId].end() )
140  {
141    StateHistoryEntry * initialEntry = new StateHistoryEntry();
[7512]142
[7508]143    initialEntry->stateId = fromStateId;
144    initialEntry->dataLength = 0;
145    initialEntry->data = NULL;
[7512]146
[7508]147    stateFrom = initialEntry;
148  }
149  else
150    stateFrom = (*it);
[7512]151
[7508]152  StateHistoryEntry * stateTo = new StateHistoryEntry();
[7512]153
[7508]154  stateTo->stateId = stateId;
155  stateTo->dataLength = neededSize;
[7731]156  stateTo->data = new byte[ neededSize ];
[7512]157
[7508]158  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
[7512]159
[7508]160  int i = 0;
161  int n;
[7631]162 
163  bool hasPermission;
[7512]164
[7559]165  // now do the actual synchronization: kick all variables to write into a common buffer
[7508]166  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
167  {
[7631]168    hasPermission = (
169            this->isServer() && (*it)->checkPermission( PERMISSION_SERVER ) ||
170            this->owner == this->hostID && (*it)->checkPermission( PERMISSION_OWNER ) ||
171            (*it)->checkPermission( PERMISSION_ALL ) 
172                    );
173   
174    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeIter == stateFrom->sizeList.end() )
[7508]175    {
[7678]176      //(*it)->debug();
[7508]177      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
178      stateTo->sizeList.push_back( n );
179      i += n;
180    }
181    else
182    {
183      for ( int j = 0; j<(*sizeIter); j++ )
184      {
185        assert( i < stateFrom->dataLength );
186        stateTo->data[i] = stateFrom->data[i];
187        i++;
188      }
189      stateTo->sizeList.push_back( (*sizeIter) );
190    }
[7512]191
[7508]192    if ( sizeIter != stateFrom->sizeList.end() )
193      sizeIter++;
194  }
[7512]195
[7508]196  sentStates[userId].push_back( stateTo );
[7591]197 
198  assert( i == neededSize );
[7512]199
[7508]200  //write diff to data
201  for ( i = 0; i<neededSize; i++ )
202  {
203    if ( i < stateFrom->dataLength )
204      data[i] = stateTo->data[i] - stateFrom->data[i];
205    else
206      data[i] = stateTo->data[i];
207  }
[7512]208
[7508]209  return neededSize;
[5997]210}
211
212/**
[7444]213 * sets a new state out of a diff created on another host
214 * @param userId hostId of user who send me that diff
215 * @param data pointer to diff
216 * @param length length of diff
217 * @param stateId id of current state
[7512]218 * @param fromStateId id of the base state id
[7591]219 * @return number bytes read
[7565]220 * @todo check for permissions
[5997]221 */
[7591]222int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
[5997]223{
[7508]224  //make sure this user has his history
225  if ( recvStates.size() <= userId )
226    recvStates.resize( userId+1 );
[7512]227
[7508]228  //create new state
229  StateHistoryEntry * stateTo = new StateHistoryEntry();
230  stateTo->stateId = stateId;
231  stateTo->dataLength = length;
[7731]232  stateTo->data = new byte[ length ];
[7512]233
234  //remove old states
[7508]235  StateHistory::iterator it = recvStates[userId].begin();
[7512]236
[7508]237  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
238    it++;
[7512]239
[7508]240  if ( it != recvStates[userId].begin() )
241  {
242    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
243    {
244      if ( (*it2)->data != NULL )
245      {
[7731]246        delete [] (*it2)->data;
[7508]247        (*it2)->data = NULL;
248      }
249    }
250    recvStates[userId].erase( recvStates[userId].begin(), it );
251  }
[7512]252
[7508]253  //find state to apply diff to
254  StateHistoryEntry * stateFrom = NULL;
[7512]255
[7508]256  it = recvStates[userId].begin();
257  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
258    it++;
[7512]259
[7508]260  if ( it == recvStates[userId].end() )
261  {
262    StateHistoryEntry * initialEntry = new StateHistoryEntry();
[7512]263
[7508]264    initialEntry->stateId = fromStateId;
265    initialEntry->dataLength = 0;
266    initialEntry->data = NULL;
[7512]267
[7508]268    stateFrom = initialEntry;
269  }
270  else
271    stateFrom = (*it);
[7614]272 
[7508]273  //apply diff
274  for ( int i = 0; i<length; i++ )
275  {
276    if ( i < stateFrom->dataLength )
277      stateTo->data[i] = stateFrom->data[i] + data[i];
278    else
279      stateTo->data[i] = data[i];
[7565]280   
[7508]281  }
[7731]282 
[7508]283  //add state to state history
284  recvStates[userId].push_back( stateTo );
[7614]285 
[7512]286  int i = 0;
[7631]287  std::list<int> changes;
288 
[7508]289  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
290  {
[7631]291    if (
292        (*it)->checkPermission( PERMISSION_SERVER ) && networkStream->isUserServer( userId ) ||
293        (*it)->checkPermission( PERMISSION_OWNER ) && this->owner == userId ||
294        (*it)->checkPermission( PERMISSION_ALL ) 
295       )
296    {
297      i += (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
298      if ( (*it)->getHasChanged() )
299        changes.push_back( (*it)->getVarId() );
300    }
301    else
302    {
[7678]303//      PRINTF(0)("DONT SET VAR BECAUSE OF PERMISSION: %s %d %d %d %d %d %d\n", (*it)->getName().c_str(), (*it)->checkPermission( PERMISSION_SERVER ), (*it)->checkPermission( PERMISSION_OWNER ), (*it)->checkPermission( PERMISSION_ALL ), networkStream->isUserServer( userId ), this->owner, userId );
[7631]304      i += (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
305    }
[7508]306  }
[7614]307
[7565]308  this->varChangeHandler( changes );
[7578]309 
[7591]310  return i;
[5997]311}
[6139]312
[7444]313 /**
314 * override this function to be notified on change
315 * of your registred variables.
316 * @param id id's which have changed
317 */
[7445]318void Synchronizeable::varChangeHandler( std::list<int> & id )
[7444]319{
320}
[6695]321
[6341]322/**
[7444]323 * registers a varable to be synchronized over network
324 * @param var see src/lib/network/synchronizeable_var/ for available classes
[6341]325 */
[7444]326void Synchronizeable::registerVar( SynchronizeableVar * var )
[6341]327{
[7631]328  PRINTF(0)("ADDING var: %s (%s)\n", var->getName().c_str(), this->getName() );
[7508]329  syncVarList.push_back( var );
[6341]330}
[6139]331
[6341]332/**
[7444]333 * registers a varable to be synchronized over network
334 * return value is passed to varChangeHandler on change
335 * @param var see src/lib/network/synchronizeable_var/ for available classes
336 * @return handle passed to varChangeHandler on changes
[6341]337 */
[7444]338int Synchronizeable::registerVarId( SynchronizeableVar * var )
[6341]339{
[7631]340  PRINTF(0)("ADDING var: %s (%s)\n", var->getName().c_str(), this->getName() );
[7508]341  syncVarList.push_back( var );
[7631]342  var->setWatched( true );
343  var->setVarId( syncVarList.size()-1 );
[7508]344  return syncVarList.size()-1;
[6341]345}
[6139]346
[7631]347/**
348 * removed user's states from memory
349 * @param userId user to clean
350 */
351void Synchronizeable::cleanUpUser( int userId )
352{
353  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
354  {
355    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it++ )
356    {
357      if ( (*it2)->data )
[7731]358        delete [] (*it2)->data;
[7631]359      (*it2)->data = NULL;
360     
[7731]361      delete [] *it2;
[7631]362    }
363  }
364 
365  sentStates.clear();
366 
367  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
368  {
369    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it++ )
370    {
371      if ( (*it2)->data )
[7731]372        delete [] (*it2)->data;
[7631]373      (*it2)->data = NULL;
374     
[7731]375      delete [] *it2;
[7631]376    }
377  }
378 
379  recvStates.clear();
380}
[6341]381
[7602]382
[7631]383
Note: See TracBrowser for help on using the repository browser.