Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added some output so synchronizeable to find strange bug. did not help :(

File size: 9.2 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/**
95 * get the diff to last acked state of userId
96 *
97 * each synchrinizeable defines its own stack of states received and sent over the network. The stack contains
98 * a per user entry for the last sent/received state This function returns a delta compressed state of the
99 * synchronizeable. This state will be transmitted over the network to the other participants
100 *
101 * @param userId user to create diff for
102 * @param data buffer to copy diff in
103 * @param maxLength max bytes to copy into data
104 * @param stateId id of current state
105 * @param fromStateId the reference state for the delta state
106 * @param priorityTH tells getStateDiff to not send element with priority \< priorityTH
107 * @return n bytes copied into data
108 */
109int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
110{
111  //make sure this user has his history
112  if ( sentStates.size() <= userId )
113    sentStates.resize( userId+1 );
114
115  //calculate needed memory
116  int neededSize = 0;
117
118  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
119    neededSize += (*it)->getSize();
120
121  assert( neededSize <= maxLength );
122
123  //remove older states from history than fromStateId
124  StateHistory::iterator it = sentStates[userId].begin();
125
126  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
127    it++;
128
129  if ( it != sentStates[userId].begin() )
130  {
131    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
132    {
133      if ( (*it2)->data != NULL )
134      {
135        delete (*it2)->data;
136        (*it2)->data = NULL;
137      }
138    }
139    sentStates[userId].erase( sentStates[userId].begin(), it );
140  }
141
142  //find state to create diff from
143  StateHistoryEntry * stateFrom = NULL;
144
145  it = sentStates[userId].begin();
146  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
147    it++;
148
149  if ( it == sentStates[userId].end() )
150  {
151    StateHistoryEntry * initialEntry = new StateHistoryEntry();
152
153    initialEntry->stateId = fromStateId;
154    initialEntry->dataLength = 0;
155    initialEntry->data = NULL;
156
157    stateFrom = initialEntry;
158  }
159  else
160    stateFrom = (*it);
161
162  StateHistoryEntry * stateTo = new StateHistoryEntry();
163
164  stateTo->stateId = stateId;
165  stateTo->dataLength = neededSize;
166  stateTo->data = (byte*)malloc( neededSize );
167
168  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
169
170  int i = 0;
171  int n;
172
173  // now do the actual synchronization: kick all variables to write into a common buffer
174  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
175  {
176    PRINTF(0)("SIZE: %d\n", syncVarList.size());
177    if ( (*it)->getPriority() >= priorityTH || sizeIter == stateFrom->sizeList.end() )
178    {
179      (*it)->debug();
180      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
181      stateTo->sizeList.push_back( n );
182      i += n;
183    }
184    else if ( ! (
185                 this->isServer() && (*it)->checkPremission( PERMISSION_SERVER ) ||
186                 this->owner == this->hostID && (*it)->checkPremission( PERMISSION_OWNER ) ||
187                 (*it)->checkPremission( PERMISSION_ALL ) 
188                ) )
189    {
190      for ( int j = 0; j < (*it)->getSize(); it++ )
191      {
192        assert(false);
193        stateTo->data[i] = 0;
194        i++;
195      }
196    }
197    else
198    {
199      for ( int j = 0; j<(*sizeIter); j++ )
200      {
201        assert( i < stateFrom->dataLength );
202        stateTo->data[i] = stateFrom->data[i];
203        i++;
204      }
205      stateTo->sizeList.push_back( (*sizeIter) );
206    }
207
208    if ( sizeIter != stateFrom->sizeList.end() )
209      sizeIter++;
210  }
211
212  sentStates[userId].push_back( stateTo );
213 
214  assert( i == neededSize );
215
216  //write diff to data
217  for ( i = 0; i<neededSize; i++ )
218  {
219    if ( i < stateFrom->dataLength )
220      data[i] = stateTo->data[i] - stateFrom->data[i];
221    else
222      data[i] = stateTo->data[i];
223  }
224
225  return neededSize;
226}
227
228/**
229 * sets a new state out of a diff created on another host
230 * @param userId hostId of user who send me that diff
231 * @param data pointer to diff
232 * @param length length of diff
233 * @param stateId id of current state
234 * @param fromStateId id of the base state id
235 * @return number bytes read
236 * @todo check for permissions
237 */
238int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
239{
240  //make sure this user has his history
241  if ( recvStates.size() <= userId )
242    recvStates.resize( userId+1 );
243
244  //create new state
245  StateHistoryEntry * stateTo = new StateHistoryEntry();
246  stateTo->stateId = stateId;
247  stateTo->dataLength = length;
248  stateTo->data = (byte*)malloc( length );
249
250  //remove old states
251  StateHistory::iterator it = recvStates[userId].begin();
252
253  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
254    it++;
255
256  if ( it != recvStates[userId].begin() )
257  {
258    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
259    {
260      if ( (*it2)->data != NULL )
261      {
262        delete (*it2)->data;
263        (*it2)->data = NULL;
264      }
265    }
266    recvStates[userId].erase( recvStates[userId].begin(), it );
267  }
268
269  //find state to apply diff to
270  StateHistoryEntry * stateFrom = NULL;
271
272  it = recvStates[userId].begin();
273  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
274    it++;
275
276  if ( it == recvStates[userId].end() )
277  {
278    StateHistoryEntry * initialEntry = new StateHistoryEntry();
279
280    initialEntry->stateId = fromStateId;
281    initialEntry->dataLength = 0;
282    initialEntry->data = NULL;
283
284    stateFrom = initialEntry;
285  }
286  else
287    stateFrom = (*it);
288 
289  std::list<int> changes;
290 
291  //apply diff
292  for ( int i = 0; i<length; i++ )
293  {
294    if ( i < stateFrom->dataLength )
295      stateTo->data[i] = stateFrom->data[i] + data[i];
296    else
297      stateTo->data[i] = data[i];
298   
299    if ( data[i] != 0 )
300      changes.push_back(i);
301  }
302
303  //add state to state history
304  recvStates[userId].push_back( stateTo );
305 
306  int i = 0;
307
308  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
309  {
310    i += (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
311  }
312
313  this->varChangeHandler( changes );
314 
315  return i;
316}
317
318 /**
319 * override this function to be notified on change
320 * of your registred variables.
321 * @param id id's which have changed
322 */
323void Synchronizeable::varChangeHandler( std::list<int> & id )
324{
325}
326
327/**
328 * registers a varable to be synchronized over network
329 * @param var see src/lib/network/synchronizeable_var/ for available classes
330 */
331void Synchronizeable::registerVar( SynchronizeableVar * var )
332{
333  syncVarList.push_back( var );
334}
335
336/**
337 * registers a varable to be synchronized over network
338 * return value is passed to varChangeHandler on change
339 * @param var see src/lib/network/synchronizeable_var/ for available classes
340 * @return handle passed to varChangeHandler on changes
341 */
342int Synchronizeable::registerVarId( SynchronizeableVar * var )
343{
344  syncVarList.push_back( var );
345  return syncVarList.size()-1;
346}
347
348
349
Note: See TracBrowser for help on using the repository browser.