Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

trunk: merged the network branche back to trunk

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