Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7559 was 7559, checked in by patrick, 18 years ago

network: added some comments and found some small bugs

File size: 8.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  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName" ) );
53}
54
55
56
57/**
58 *  default destructor deletes all unneded stuff
59 */
60Synchronizeable::~Synchronizeable()
61{
62  if ( this->networkStream )
63    this->networkStream->disconnectSynchronizeable(*this);
64}
65
66/**
67 * Sets the server flag to a given value
68 * @param isServer: the boolean value which the server flag is to set to
69 */
70void Synchronizeable::setIsServer(bool isServer)
71{
72  if( isServer )
73    this->state = this->state | STATE_SERVER;
74  else
75    this->state = this->state & (~STATE_SERVER);
76}
77
78
79/**
80 * Determines if the server flag is set
81 * @return true, if the server flag is true, false else
82 */
83bool Synchronizeable::isServer()
84{
85  return (this->state & STATE_SERVER) >0;
86}
87
88
89/**
90 * get the diff to last acked state of userId
91 *
92 * each synchrinizeable defines its own stack of states received and sent over the network. The stack contains
93 * a per user entry for the last sent/received state This function returns a delta compressed state of the
94 * synchronizeable. This state will be transmitted over the network to the other participants
95 *
96 * @param userId user to create diff for
97 * @param data buffer to copy diff in
98 * @param maxLength max bytes to copy into data
99 * @param stateId id of current state
100 * @param fromStateId the reference state for the delta state
101 * @param priorityTH tells getStateDiff to not send element with priority \< priorityTH
102 * @return n bytes copied into data
103 */
104int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
105{
106  //make sure this user has his history
107  if ( sentStates.size() <= userId )
108    sentStates.resize( userId+1 );
109
110  //calculate needed memory
111  int neededSize = 0;
112
113  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
114    neededSize += (*it)->getSize();
115
116  assert( neededSize <= maxLength );
117
118  //remove older states from history than fromStateId
119  StateHistory::iterator it = sentStates[userId].begin();
120
121  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
122    it++;
123  ///FIXED: altered begin() -> end()
124  if ( it != sentStates[userId].end() )
125  {
126    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
127    {
128      if ( (*it2)->data != NULL )
129      {
130        delete (*it2)->data;
131        (*it2)->data = NULL;
132      }
133    }
134    sentStates[userId].erase( sentStates[userId].begin(), it );
135  }
136
137  //find state to create diff from
138  StateHistoryEntry * stateFrom = NULL;
139
140  it = sentStates[userId].begin();
141  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
142    it++;
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 = (byte*)malloc( neededSize );
162
163  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
164
165  int i = 0;
166  int n;
167
168  // now do the actual synchronization: kick all variables to write into a common buffer
169  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
170  {
171    if ( (*it)->getPriority() >= priorityTH || sizeIter == stateFrom->sizeList.end() )
172    {
173      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
174      stateTo->sizeList.push_back( n );
175      i += n;
176    }
177    else
178    {
179      for ( int j = 0; j<(*sizeIter); j++ )
180      {
181        assert( i < stateFrom->dataLength );
182        stateTo->data[i] = stateFrom->data[i];
183        i++;
184      }
185      stateTo->sizeList.push_back( (*sizeIter) );
186    }
187
188    if ( sizeIter != stateFrom->sizeList.end() )
189      sizeIter++;
190  }
191
192  sentStates[userId].push_back( stateTo );
193
194  //write diff to data
195  for ( i = 0; i<neededSize; i++ )
196  {
197    if ( i < stateFrom->dataLength )
198      data[i] = stateTo->data[i] - stateFrom->data[i];
199    else
200      data[i] = stateTo->data[i];
201  }
202
203  return neededSize;
204}
205
206/**
207 * sets a new state out of a diff created on another host
208 * @param userId hostId of user who send me that diff
209 * @param data pointer to diff
210 * @param length length of diff
211 * @param stateId id of current state
212 * @param fromStateId id of the base state id
213 * @return true on success
214 */
215bool Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
216{
217  //make sure this user has his history
218  if ( recvStates.size() <= userId )
219    recvStates.resize( userId+1 );
220
221  //create new state
222  StateHistoryEntry * stateTo = new StateHistoryEntry();
223  stateTo->stateId = stateId;
224  stateTo->dataLength = length;
225  stateTo->data = (byte*)malloc( length );
226
227  //remove old states
228  StateHistory::iterator it = recvStates[userId].begin();
229
230  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
231    it++;
232
233  if ( it != recvStates[userId].begin() )
234  {
235    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
236    {
237      if ( (*it2)->data != NULL )
238      {
239        delete (*it2)->data;
240        (*it2)->data = NULL;
241      }
242    }
243    recvStates[userId].erase( recvStates[userId].begin(), it );
244  }
245
246  //find state to apply diff to
247  StateHistoryEntry * stateFrom = NULL;
248
249  it = recvStates[userId].begin();
250  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
251    it++;
252
253  if ( it == recvStates[userId].end() )
254  {
255    StateHistoryEntry * initialEntry = new StateHistoryEntry();
256
257    initialEntry->stateId = fromStateId;
258    initialEntry->dataLength = 0;
259    initialEntry->data = NULL;
260
261    stateFrom = initialEntry;
262  }
263  else
264    stateFrom = (*it);
265
266  //apply diff
267  for ( int i = 0; i<length; i++ )
268  {
269    if ( i < stateFrom->dataLength )
270      stateTo->data[i] = stateFrom->data[i] + data[i];
271    else
272      stateTo->data[i] = data[i];
273  }
274
275  //add state to state history
276  recvStates[userId].push_back( stateTo );
277
278  int i = 0;
279
280  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
281  {
282    i += (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
283  }
284
285  assert( i == length -1 );
286
287  return length;
288}
289
290 /**
291 * override this function to be notified on change
292 * of your registred variables.
293 * @param id id's which have changed
294 */
295void Synchronizeable::varChangeHandler( std::list<int> & id )
296{
297}
298
299/**
300 * registers a varable to be synchronized over network
301 * @param var see src/lib/network/synchronizeable_var/ for available classes
302 */
303void Synchronizeable::registerVar( SynchronizeableVar * var )
304{
305  syncVarList.push_back( var );
306}
307
308/**
309 * registers a varable to be synchronized over network
310 * return value is passed to varChangeHandler on change
311 * @param var see src/lib/network/synchronizeable_var/ for available classes
312 * @return handle passed to varChangeHandler on changes
313 */
314int Synchronizeable::registerVarId( SynchronizeableVar * var )
315{
316  syncVarList.push_back( var );
317  return syncVarList.size()-1;
318}
319
320
Note: See TracBrowser for help on using the repository browser.