Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/network/synchronizeable.cc @ 8927

Last change on this file since 8927 was 8708, checked in by bensch, 18 years ago

merged network back
merged with command:
svn merge -r8625:HEAD https://svn.orxonox.net/orxonox/branches/network .
no conflicts

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