Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

more string switching for outcommented stuff

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