Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7793 was 7793, checked in by rennerc, 19 years ago

fixed da bug

File size: 10.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
23#include "state.h"
24
25#include <cassert>
26
27#include "synchronizeable.h"
28
29
30
31/**
32 *  default constructor
33 */
34Synchronizeable::Synchronizeable()
35{
36  this->setClassID(CL_SYNCHRONIZEABLE, "Synchronizeable");
37  this->owner = -1;
38  this->hostID = SharedNetworkData::getInstance()->getHostID();
39  this->setIsServer(this->hostID == 0);
40  this->uniqueID = NET_UID_UNASSIGNED;
41  this->networkStream = NULL;
42  this->bSynchronize = false;
43 
44  if( State::isOnline())
45  {
46    NetworkStream* nd = SharedNetworkData::getInstance()->getDefaultSyncStream();
47    assert(nd != NULL);
48    nd->connectSynchronizeable(*this);
49    this->setUniqueID(SharedNetworkData::getInstance()->getNewUniqueID());
50  }
51
52  /* make sure loadClassId is first synced var because this is read by networkStream */
53  assert( syncVarList.size() == 0 );
54  mLeafClassId = this->registerVarId( new SynchronizeableInt( (int*)&this->getLeafClassID(), (int*)&this->getLeafClassID(), "leafClassId" ) );
55   
56  this->registerVar( new SynchronizeableInt( &this->owner, &this->owner, "owner" ) );
57  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName" ) );
58}
59
60
61
62/**
63 *  default destructor deletes all unneded stuff
64 */
65Synchronizeable::~Synchronizeable()
66{
67  if ( this->networkStream )
68    this->networkStream->disconnectSynchronizeable(*this);
69}
70
71/**
72 * Sets the server flag to a given value
73 * @param isServer: the boolean value which the server flag is to set to
74 */
75void Synchronizeable::setIsServer(bool isServer)
76{
77  if( isServer )
78    this->state = this->state | STATE_SERVER;
79  else
80    this->state = this->state & (~STATE_SERVER);
81}
82
83
84/**
85 * Determines if the server flag is set
86 * @return true, if the server flag is true, false else
87 */
88bool Synchronizeable::isServer()
89{
90  return (this->state & STATE_SERVER) >0;
91}
92
93
94
95int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
96{
97  //make sure this user has his history
98  if ( sentStates.size() <= userId )
99    sentStates.resize( userId+1 );
100
101  //calculate needed memory
102  int neededSize = 0;
103
104  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
105    neededSize += (*it)->getSize();
106
107  if ( !( neededSize <= maxLength ) )
108  {
109    PRINTF(0)( "%d > %d\n", neededSize, maxLength );
110    assert(false);
111  }
112
113  //remove older states from history than fromStateId
114  StateHistory::iterator it = sentStates[userId].begin();
115
116  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
117    it++;
118
119  if ( it != sentStates[userId].begin() )
120  {
121    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
122    {
123      if ( (*it2)->data != NULL )
124      {
125        delete [] (*it2)->data;
126        (*it2)->data = NULL;
127      }
128    }
129    sentStates[userId].erase( sentStates[userId].begin(), it );
130  }
131
132  //find state to create diff from
133  StateHistoryEntry * stateFrom = NULL;
134
135  it = sentStates[userId].begin();
136  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
137    it++;
138 
139//  if ( getLeafClassID() == CL_SPACE_SHIP )
140//  {
141//    PRINTF(0)("getStateDiff:SpaceShip from: %d stateId: %d\n", (it == sentStates[userId].end())?-1:fromStateId, stateId);
142//  }
143
144  if ( it == sentStates[userId].end() )
145  {
146    StateHistoryEntry * initialEntry = new StateHistoryEntry();
147
148    initialEntry->stateId = fromStateId;
149    initialEntry->dataLength = 0;
150    initialEntry->data = NULL;
151
152    stateFrom = initialEntry;
153  }
154  else
155    stateFrom = (*it);
156
157  StateHistoryEntry * stateTo = new StateHistoryEntry();
158
159  stateTo->stateId = stateId;
160  stateTo->dataLength = neededSize;
161  stateTo->data = new byte[ neededSize ];
162
163  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
164
165  int i = 0;
166  int n;
167 
168  bool hasPermission;
169
170  // now do the actual synchronization: kick all variables to write into a common buffer
171  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
172  {
173    hasPermission = (
174            this->isServer() && (*it)->checkPermission( PERMISSION_SERVER ) ||
175            this->owner == this->hostID && (*it)->checkPermission( PERMISSION_OWNER ) ||
176            (*it)->checkPermission( PERMISSION_ALL ) 
177                    );
178   
179    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeIter == stateFrom->sizeList.end() )
180    {
181      //(*it)->debug();
182      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
183      stateTo->sizeList.push_back( n );
184      i += n;
185    }
186    else
187    {
188      for ( int j = 0; j<(*sizeIter); j++ )
189      {
190        assert( i < stateFrom->dataLength );
191        stateTo->data[i] = stateFrom->data[i];
192        i++;
193      }
194      stateTo->sizeList.push_back( (*sizeIter) );
195    }
196
197    if ( sizeIter != stateFrom->sizeList.end() )
198      sizeIter++;
199  }
200
201  sentStates[userId].push_back( stateTo );
202 
203  assert( i == neededSize );
204
205  //write diff to data
206  for ( i = 0; i<neededSize; i++ )
207  {
208    if ( i < stateFrom->dataLength )
209      data[i] = stateTo->data[i] - stateFrom->data[i];
210    else
211      data[i] = stateTo->data[i];
212  }
213
214  return neededSize;
215}
216
217/**
218 * sets a new state out of a diff created on another host
219 * @param userId hostId of user who send me that diff
220 * @param data pointer to diff
221 * @param length length of diff
222 * @param stateId id of current state
223 * @param fromStateId id of the base state id
224 * @return number bytes read
225 * @todo check for permissions
226 */
227int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
228{
229  //make sure this user has his history
230  if ( recvStates.size() <= userId )
231    recvStates.resize( userId+1 );
232
233  //create new state
234  StateHistoryEntry * stateTo = new StateHistoryEntry();
235  stateTo->stateId = stateId;
236  stateTo->dataLength = length;
237  stateTo->data = new byte[ length ];
238
239  //remove old states
240  StateHistory::iterator it = recvStates[userId].begin();
241
242  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
243    it++;
244
245  if ( it != recvStates[userId].begin() )
246  {
247    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
248    {
249      if ( (*it2)->data != NULL )
250      {
251        delete [] (*it2)->data;
252        (*it2)->data = NULL;
253      }
254    }
255    recvStates[userId].erase( recvStates[userId].begin(), it );
256  }
257
258  //find state to apply diff to
259  StateHistoryEntry * stateFrom = NULL;
260
261  it = recvStates[userId].begin();
262  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
263    it++;
264 
265//  if ( getLeafClassID() == CL_SPACE_SHIP )
266//  {
267//    PRINTF(0)("setStateDiff:SpaceShip from: %d stateId: %d\n", (it == recvStates[userId].end())?-1:fromStateId, stateId);
268//  }
269
270  if ( it == recvStates[userId].end() )
271  {
272    StateHistoryEntry * initialEntry = new StateHistoryEntry();
273
274    initialEntry->stateId = fromStateId;
275    initialEntry->dataLength = 0;
276    initialEntry->data = NULL;
277
278    stateFrom = initialEntry;
279  }
280  else
281    stateFrom = (*it);
282 
283  //apply diff
284  for ( int i = 0; i<length; i++ )
285  {
286    if ( i < stateFrom->dataLength )
287      stateTo->data[i] = stateFrom->data[i] + data[i];
288    else
289      stateTo->data[i] = data[i];
290   
291  }
292 
293  //add state to state history
294  recvStates[userId].push_back( stateTo );
295 
296  int i = 0;
297  std::list<int> changes;
298 
299  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
300  {
301    if (
302        (*it)->checkPermission( PERMISSION_SERVER ) && networkStream->isUserServer( userId ) ||
303        (*it)->checkPermission( PERMISSION_OWNER ) && this->owner == userId ||
304        (*it)->checkPermission( PERMISSION_ALL ) 
305       )
306    {
307      i += (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
308      if ( (*it)->getHasChanged() )
309        changes.push_back( (*it)->getVarId() );
310    }
311    else
312    {
313//      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 );
314      i += (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
315    }
316  }
317
318  this->varChangeHandler( changes );
319 
320  return i;
321}
322
323 /**
324 * override this function to be notified on change
325 * of your registred variables.
326 * @param id id's which have changed
327 */
328void Synchronizeable::varChangeHandler( std::list<int> & id )
329{
330}
331
332/**
333 * registers a varable to be synchronized over network
334 * @param var see src/lib/network/synchronizeable_var/ for available classes
335 */
336void Synchronizeable::registerVar( SynchronizeableVar * var )
337{
338  syncVarList.push_back( var );
339}
340
341/**
342 * registers a varable to be synchronized over network
343 * return value is passed to varChangeHandler on change
344 * @param var see src/lib/network/synchronizeable_var/ for available classes
345 * @return handle passed to varChangeHandler on changes
346 */
347int Synchronizeable::registerVarId( SynchronizeableVar * var )
348{
349  syncVarList.push_back( var );
350  var->setWatched( true );
351  var->setVarId( syncVarList.size()-1 );
352  return syncVarList.size()-1;
353}
354
355/**
356 * removed user's states from memory
357 * @param userId user to clean
358 */
359void Synchronizeable::cleanUpUser( int userId )
360{
361  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
362  {
363    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
364    {
365      if ( (*it2)->data )
366        delete [] (*it2)->data;
367      (*it2)->data = NULL;
368     
369      delete *it2;
370    }
371  }
372 
373  sentStates.clear();
374 
375  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
376  {
377    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
378    {
379      if ( (*it2)->data )
380        delete [] (*it2)->data;
381      (*it2)->data = NULL;
382     
383      delete *it2;
384    }
385  }
386 
387  recvStates.clear();
388}
389
390
391
Note: See TracBrowser for help on using the repository browser.