Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

tighten up the interface

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