Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

probably fixed bug

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