Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

trunk: merged the network branche back to trunk.

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