Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8155 was 8147, checked in by bensch, 18 years ago

orxonox/trunk: merged the network branche back here
merged with command:
svn merge -r8070:HEAD https://svn.orxonox.net/orxonox/branches/network .
no conflicts

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