Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

more framework switch

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