Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8273 was 8273, checked in by rennerc, 18 years ago

removed some memory leaks

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