Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

fixed some bugs

File size: 9.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 );
[7575]54  this->registerVar( new SynchronizeableInt( (int*)&this->getLeafClassID(), (int*)&this->getLeafClassID(), "leafClassId" ) );
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
[5997]94/**
[7444]95 * get the diff to last acked state of userId
[7559]96 *
97 * each synchrinizeable defines its own stack of states received and sent over the network. The stack contains
98 * a per user entry for the last sent/received state This function returns a delta compressed state of the
99 * synchronizeable. This state will be transmitted over the network to the other participants
100 *
[7444]101 * @param userId user to create diff for
102 * @param data buffer to copy diff in
103 * @param maxLength max bytes to copy into data
104 * @param stateId id of current state
[7559]105 * @param fromStateId the reference state for the delta state
[7444]106 * @param priorityTH tells getStateDiff to not send element with priority \< priorityTH
107 * @return n bytes copied into data
[5997]108 */
[7508]109int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
[5997]110{
[7508]111  //make sure this user has his history
112  if ( sentStates.size() <= userId )
113    sentStates.resize( userId+1 );
[7512]114
[7508]115  //calculate needed memory
116  int neededSize = 0;
[7512]117
[7508]118  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
119    neededSize += (*it)->getSize();
[7512]120
[7508]121  assert( neededSize <= maxLength );
[7512]122
[7508]123  //remove older states from history than fromStateId
124  StateHistory::iterator it = sentStates[userId].begin();
[7512]125
[7508]126  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
127    it++;
[7559]128  ///FIXED: altered begin() -> end()
129  if ( it != sentStates[userId].end() )
[7508]130  {
131    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
132    {
133      if ( (*it2)->data != NULL )
134      {
135        delete (*it2)->data;
136        (*it2)->data = NULL;
137      }
138    }
139    sentStates[userId].erase( sentStates[userId].begin(), it );
140  }
[7512]141
[7508]142  //find state to create diff from
143  StateHistoryEntry * stateFrom = NULL;
[7512]144
[7508]145  it = sentStates[userId].begin();
146  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
147    it++;
[7512]148
[7508]149  if ( it == sentStates[userId].end() )
150  {
151    StateHistoryEntry * initialEntry = new StateHistoryEntry();
[7512]152
[7508]153    initialEntry->stateId = fromStateId;
154    initialEntry->dataLength = 0;
155    initialEntry->data = NULL;
[7512]156
[7508]157    stateFrom = initialEntry;
158  }
159  else
160    stateFrom = (*it);
[7512]161
[7508]162  StateHistoryEntry * stateTo = new StateHistoryEntry();
[7512]163
[7508]164  stateTo->stateId = stateId;
165  stateTo->dataLength = neededSize;
166  stateTo->data = (byte*)malloc( neededSize );
[7512]167
[7508]168  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
[7512]169
[7508]170  int i = 0;
171  int n;
[7512]172
[7559]173  // now do the actual synchronization: kick all variables to write into a common buffer
[7508]174  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
175  {
176    if ( (*it)->getPriority() >= priorityTH || sizeIter == stateFrom->sizeList.end() )
177    {
178      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
179      stateTo->sizeList.push_back( n );
180      i += n;
181    }
[7565]182    else if ( ! (
183                 this->isServer() && (*it)->checkPremission( PERMISSION_SERVER ) ||
184                 this->owner == this->hostID && (*it)->checkPremission( PERMISSION_OWNER ) ||
185                 (*it)->checkPremission( PERMISSION_ALL ) 
186                ) )
187    {
188      for ( int j = 0; j < (*it)->getSize(); it++ )
189      {
190        stateTo->data[i] = 0;
191        i++;
192      }
193    }
[7508]194    else
195    {
196      for ( int j = 0; j<(*sizeIter); j++ )
197      {
198        assert( i < stateFrom->dataLength );
199        stateTo->data[i] = stateFrom->data[i];
200        i++;
201      }
202      stateTo->sizeList.push_back( (*sizeIter) );
203    }
[7512]204
[7508]205    if ( sizeIter != stateFrom->sizeList.end() )
206      sizeIter++;
207  }
[7512]208
[7508]209  sentStates[userId].push_back( stateTo );
[7512]210
[7508]211  //write diff to data
212  for ( i = 0; i<neededSize; i++ )
213  {
214    if ( i < stateFrom->dataLength )
215      data[i] = stateTo->data[i] - stateFrom->data[i];
216    else
217      data[i] = stateTo->data[i];
218  }
[7512]219
[7508]220  return neededSize;
[5997]221}
222
223/**
[7444]224 * sets a new state out of a diff created on another host
225 * @param userId hostId of user who send me that diff
226 * @param data pointer to diff
227 * @param length length of diff
228 * @param stateId id of current state
[7512]229 * @param fromStateId id of the base state id
[7444]230 * @return true on success
[7565]231 * @todo check for permissions
[5997]232 */
[7508]233bool Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
[5997]234{
[7508]235  //make sure this user has his history
236  if ( recvStates.size() <= userId )
237    recvStates.resize( userId+1 );
[7512]238
[7508]239  //create new state
240  StateHistoryEntry * stateTo = new StateHistoryEntry();
241  stateTo->stateId = stateId;
242  stateTo->dataLength = length;
243  stateTo->data = (byte*)malloc( length );
[7512]244
245  //remove old states
[7508]246  StateHistory::iterator it = recvStates[userId].begin();
[7512]247
[7508]248  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
249    it++;
[7512]250
[7508]251  if ( it != recvStates[userId].begin() )
252  {
253    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
254    {
255      if ( (*it2)->data != NULL )
256      {
257        delete (*it2)->data;
258        (*it2)->data = NULL;
259      }
260    }
261    recvStates[userId].erase( recvStates[userId].begin(), it );
262  }
[7512]263
[7508]264  //find state to apply diff to
265  StateHistoryEntry * stateFrom = NULL;
[7512]266
[7508]267  it = recvStates[userId].begin();
268  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
269    it++;
[7512]270
[7508]271  if ( it == recvStates[userId].end() )
272  {
273    StateHistoryEntry * initialEntry = new StateHistoryEntry();
[7512]274
[7508]275    initialEntry->stateId = fromStateId;
276    initialEntry->dataLength = 0;
277    initialEntry->data = NULL;
[7512]278
[7508]279    stateFrom = initialEntry;
280  }
281  else
282    stateFrom = (*it);
[7512]283
[7565]284  std::list<int> changes;
285 
[7508]286  //apply diff
287  for ( int i = 0; i<length; i++ )
288  {
289    if ( i < stateFrom->dataLength )
290      stateTo->data[i] = stateFrom->data[i] + data[i];
291    else
292      stateTo->data[i] = data[i];
[7565]293   
294    if ( data[i] != 0 )
295      changes.push_back(i);
[7508]296  }
[7512]297
[7508]298  //add state to state history
299  recvStates[userId].push_back( stateTo );
[7512]300
301  int i = 0;
302
[7508]303  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
304  {
305    i += (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
306  }
[7565]307 
308  this->varChangeHandler( changes );
[7512]309
[7575]310  assert( i == length );
[7512]311
[7508]312  return length;
[5997]313}
[6139]314
[7444]315 /**
316 * override this function to be notified on change
317 * of your registred variables.
318 * @param id id's which have changed
319 */
[7445]320void Synchronizeable::varChangeHandler( std::list<int> & id )
[7444]321{
322}
[6695]323
[6341]324/**
[7444]325 * registers a varable to be synchronized over network
326 * @param var see src/lib/network/synchronizeable_var/ for available classes
[6341]327 */
[7444]328void Synchronizeable::registerVar( SynchronizeableVar * var )
[6341]329{
[7508]330  syncVarList.push_back( var );
[6341]331}
[6139]332
[6341]333/**
[7444]334 * registers a varable to be synchronized over network
335 * return value is passed to varChangeHandler on change
336 * @param var see src/lib/network/synchronizeable_var/ for available classes
337 * @return handle passed to varChangeHandler on changes
[6341]338 */
[7444]339int Synchronizeable::registerVarId( SynchronizeableVar * var )
[6341]340{
[7508]341  syncVarList.push_back( var );
342  return syncVarList.size()-1;
[6341]343}
[6139]344
[6341]345
Note: See TracBrowser for help on using the repository browser.