Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

new NetworkGameManager works now

File size: 14.5 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 = 0;
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            this->isServer() && this->owner != userId && (*it)->checkPermission( PERMISSION_OWNER ) ||
178            (*it)->checkPermission( PERMISSION_ALL ) 
179                    );
180   
181    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeIter == stateFrom->sizeList.end() )
182    {
183      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
184      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
185      stateTo->sizeList.push_back( n );
186      //(*it)->debug();
187      i += n;
188    }
189    else
190    {
191      for ( int j = 0; j<(*sizeIter); j++ )
192      {
193        assert( i < stateFrom->dataLength );
194        stateTo->data[i] = stateFrom->data[i];
195        i++;
196      }
197      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
198      stateTo->sizeList.push_back( (*sizeIter) );
199    }
200
201    if ( sizeIter != stateFrom->sizeList.end() )
202      sizeIter++;
203  }
204
205  sentStates[userId].push_back( stateTo );
206 
207  assert( i == neededSize );
208
209  //write diff to data
210  for ( i = 0; i<neededSize; i++ )
211  {
212    if ( i < stateFrom->dataLength )
213      data[i] = stateTo->data[i] - stateFrom->data[i];
214    else
215      data[i] = stateTo->data[i];
216  }
217
218  return neededSize;
219}
220
221/**
222 * sets a new state out of a diff created on another host
223 * @param userId hostId of user who send me that diff
224 * @param data pointer to diff
225 * @param length length of diff
226 * @param stateId id of current state
227 * @param fromStateId id of the base state id
228 * @return number bytes read
229 * @todo check for permissions
230 */
231int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
232{
233  //make sure this user has his history
234  if ( recvStates.size() <= userId )
235    recvStates.resize( userId+1 );
236
237  //create new state
238  StateHistoryEntry * stateTo = new StateHistoryEntry();
239  stateTo->stateId = stateId;
240  stateTo->dataLength = length;
241  stateTo->data = new byte[ length ];
242
243
244  //find state to apply diff to
245  StateHistoryEntry * stateFrom = NULL;
246
247  StateHistory::iterator it = recvStates[userId].begin();
248  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
249    it++;
250
251 
252//  if ( getLeafClassID() == CL_SPACE_SHIP )
253//  {
254//    PRINTF(0)("setStateDiff:SpaceShip from: %d stateId: %d\n", (it == recvStates[userId].end())?-1:fromStateId, stateId);
255//  }
256
257  if ( it == recvStates[userId].end() )
258  {
259    StateHistoryEntry * initialEntry = new StateHistoryEntry();
260
261    initialEntry->stateId = fromStateId;
262    initialEntry->dataLength = 0;
263    initialEntry->data = NULL;
264
265    stateFrom = initialEntry;
266  }
267  else
268    stateFrom = (*it);
269 
270  //apply diff
271  for ( int i = 0; i<length; i++ )
272  {
273    if ( i < stateFrom->dataLength )
274      stateTo->data[i] = stateFrom->data[i] + data[i];
275    else
276      stateTo->data[i] = data[i];
277   
278  }
279 
280  //add state to state history
281  recvStates[userId].push_back( stateTo );
282 
283  int i = 0;
284  int n = 0;
285  std::list<int> changes;
286 
287  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
288  {
289    if (
290        (*it)->checkPermission( PERMISSION_SERVER ) && networkStream->isUserServer( userId ) ||
291        (*it)->checkPermission( PERMISSION_OWNER ) && this->owner == userId ||
292        networkStream->isUserServer( userId ) && this->owner != getHostID() && (*it)->checkPermission( PERMISSION_OWNER ) ||
293        (*it)->checkPermission( PERMISSION_ALL ) 
294       )
295    {
296      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
297      i += n;
298      //NETPRINTF(0)("%s::setvar %s %d\n", getClassName(), (*it)->getName().c_str(), n);
299      //(*it)->debug();
300      if ( (*it)->getHasChanged() )
301      {
302        changes.push_back( (*it)->getVarId() );
303      }
304    }
305    else
306    {
307//      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 );
308      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
309      //NETPRINTF(0)("%s::setvar %s %d\n", getClassName(), (*it)->getName().c_str(), n);
310      //(*it)->debug();
311      i += n;
312    }
313  }
314
315  this->varChangeHandler( changes );
316 
317  return i;
318}
319
320 /**
321 * override this function to be notified on change
322 * of your registred variables.
323 * @param id id's which have changed
324 */
325void Synchronizeable::varChangeHandler( std::list<int> & id )
326{
327}
328
329/**
330 * registers a varable to be synchronized over network
331 * @param var see src/lib/network/synchronizeable_var/ for available classes
332 */
333void Synchronizeable::registerVar( SynchronizeableVar * var )
334{
335  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
336  syncVarList.push_back( var );
337}
338
339/**
340 * registers a varable to be synchronized over network
341 * return value is passed to varChangeHandler on change
342 * @param var see src/lib/network/synchronizeable_var/ for available classes
343 * @return handle passed to varChangeHandler on changes
344 */
345int Synchronizeable::registerVarId( SynchronizeableVar * var )
346{
347  //PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
348  syncVarList.push_back( var );
349  var->setWatched( true );
350  var->setVarId( syncVarList.size()-1 );
351  return syncVarList.size()-1;
352}
353
354/**
355 * removed user's states from memory
356 * @param userId user to clean
357 */
358void Synchronizeable::cleanUpUser( int userId )
359{
360  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
361  {
362    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
363    {
364      if ( (*it2)->data )
365        delete [] (*it2)->data;
366      (*it2)->data = NULL;
367     
368      delete *it2;
369    }
370  }
371 
372  sentStates.clear();
373 
374  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
375  {
376    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
377    {
378      if ( (*it2)->data )
379        delete [] (*it2)->data;
380      (*it2)->data = NULL;
381     
382      delete *it2;
383    }
384  }
385 
386  recvStates.clear();
387}
388
389/**
390 * this function is called after recieving a state.
391 * @param userId
392 * @param stateId
393 * @param fromStateId
394 */
395void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
396{
397   //make sure this user has his history
398  if ( recvStates.size() <= userId )
399    recvStates.resize( userId+1 );
400 
401  //remove old states
402  StateHistory::iterator it = recvStates[userId].begin();
403
404#if 0
405  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
406    it++;
407
408  if ( it != recvStates[userId].begin() )
409  {
410    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
411    {
412      if ( (*it2)->data != NULL )
413      {
414        delete [] (*it2)->data;
415        (*it2)->data = NULL;
416      }
417    }
418    recvStates[userId].erase( recvStates[userId].begin(), it );
419  }
420#endif
421
422  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
423  {
424    if ( (*it)->stateId < fromStateId )
425    {
426      StateHistory::iterator delIt = it;
427      it ++;
428     
429      if ( (*delIt)->data )
430        delete [] (*delIt)->data;
431      recvStates[userId].erase( delIt );
432     
433      continue;
434    }
435    it++;
436  }
437 
438  StateHistory::iterator fromState = recvStates[userId].end();
439  StateHistory::iterator toState = recvStates[userId].end();
440 
441  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
442  {
443    if ( (*it)->stateId == stateId )
444      toState = it;
445    if ( (*it)->stateId == fromStateId )
446      fromState = it;
447   
448    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
449      break;
450  }
451 
452  // setStateDiff was not called and i know fromStateId
453  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
454  {
455    StateHistoryEntry * entry = new StateHistoryEntry;
456   
457    entry->dataLength = (*fromState)->dataLength;
458    if ( entry->dataLength > 0 )
459    {
460      entry->data = new byte[entry->dataLength];
461         
462      assert( (*fromState)->data );
463      memcpy( entry->data, (*fromState)->data, entry->dataLength );
464    }
465    else
466      entry->data = NULL;
467   
468    entry->sizeList = (*fromState)->sizeList;
469    entry->stateId = stateId;
470   
471    recvStates[userId].push_back(entry);
472  }
473}
474
475/**
476 * this function is called after sending a state
477 * @param userId
478 * @param stateId
479 * @param fromStateId
480 */
481void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
482{
483   //make sure this user has his history
484  if ( sentStates.size() <= userId )
485    sentStates.resize( userId+1 );
486
487   //remove old states
488  StateHistory::iterator it = sentStates[userId].begin();
489
490  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
491  {
492    if ( (*it)->stateId < fromStateId )
493    {
494      StateHistory::iterator delIt = it;
495      it ++;
496     
497      if ( (*delIt)->data )
498        delete [] (*delIt)->data;
499      sentStates[userId].erase( delIt );
500     
501      continue;
502    }
503    it++;
504  }
505
506 
507  StateHistory::iterator fromState = sentStates[userId].end();
508  StateHistory::iterator toState = sentStates[userId].end();
509 
510  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
511  {
512    if ( (*it)->stateId == stateId )
513      toState = it;
514    if ( (*it)->stateId == fromStateId )
515      fromState = it;
516   
517    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
518      break;
519  }
520
521 
522  // getStateDiff was not called and i know fromStateId
523  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
524  {
525    StateHistoryEntry * entry = new StateHistoryEntry;
526   
527    entry->dataLength = (*fromState)->dataLength;
528    if ( entry->dataLength > 0 )
529    {
530      entry->data = new byte[entry->dataLength];
531     
532      assert( (*fromState)->data );
533      memcpy( entry->data, (*fromState)->data, entry->dataLength );
534    }
535    else
536      entry->data = NULL;
537   
538    entry->sizeList = (*fromState)->sizeList;
539    entry->stateId = stateId;
540   
541    sentStates[userId].push_back(entry);
542  }
543 
544}
545
546
547
Note: See TracBrowser for help on using the repository browser.