Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9389 was 9386, checked in by bensch, 19 years ago

orxonox/proxy: removed the dependency of the netdefs in pnode, which should decrease compile time enormously.

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