Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

reimplemented NetworkStream

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