Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/Synchronisable.cc @ 1741

Last change on this file since 1741 was 1741, checked in by scheusso, 16 years ago

compressing doesnt work yet (maybe rather decompressing)

  • Property svn:eol-style set to native
File size: 16.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Dumeni Manatschal, (C) 2007
24 *      Oliver Scheuss, (C) 2007
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30//
31// C++ Implementation: synchronisable
32//
33// Description:
34//
35//
36// Author:  Dumeni, Oliver Scheuss, (C) 2007
37//
38// Copyright: See COPYING file that comes with this distribution
39//
40
41#include "Synchronisable.h"
42
43#include <string>
44#include <iostream>
45#include <assert.h>
46
47#include "core/CoreIncludes.h"
48#include "core/BaseObject.h"
49// #include "core/Identifier.h"
50
51namespace network
52{
53
54
55  int Synchronisable::state_=0x1; // detemines wheter we are server (default) or client
56
57  /**
58  * Constructor:
59  * calls registarAllVariables, that has to be implemented by the inheriting classID
60  */
61  Synchronisable::Synchronisable(){
62    RegisterRootObject(Synchronisable);
63    static int idCounter=0;
64    datasize=0;
65    objectID=idCounter++;
66    syncList = new std::list<synchronisableVariable *>;
67    //registerAllVariables();
68  }
69
70  Synchronisable::~Synchronisable(){
71    // delete callback function objects
72    if(!orxonox::Identifier::isCreatingHierarchy())
73      for(std::list<synchronisableVariable *>::iterator it = syncList->begin(); it!=syncList->end(); it++)
74        delete (*it)->callback;
75  }
76
77  bool Synchronisable::create(){
78    this->classID = this->getIdentifier()->getNetworkID();
79    COUT(4) << "creating synchronisable: setting classid from " << this->getIdentifier()->getName() << " to: " << classID << std::endl;
80    return true;
81  }
82
83  void Synchronisable::setClient(bool b){
84    if(b) // client
85      state_=0x2;
86    else  // server
87      state_=0x1;
88  }
89 
90  bool Synchronisable::fabricate(unsigned char*& mem, int mode)
91  {
92    unsigned int size, objectID, classID;
93    size = *(unsigned int *)mem;
94    objectID = *(unsigned int*)(mem+sizeof(unsigned int));
95    classID = *(unsigned int*)(mem+2*sizeof(unsigned int));
96   
97    orxonox::Identifier* id = ID(classID);
98    if(!id){
99      COUT(3) << "We could not identify a new object; classid: " << classID << " uint: " << (unsigned int)classID << " objectID: " << objectID << " size: " << size << std::endl;
100      assert(0);
101      return false; // most probably the gamestate is corrupted
102    }
103    orxonox::BaseObject *bo = id->fabricate();
104    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
105    assert(no);
106    no->objectID=objectID;
107    no->classID=classID;
108    COUT(3) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
109          // update data and create object/entity...
110    if( !no->updateData(mem, mode) ){
111      COUT(1) << "We couldn't update the object: " << objectID << std::endl;
112      return false;
113    }
114    if( !no->create() )
115    {
116      COUT(1) << "We couldn't manifest (create() ) the object: " << objectID << std::endl;
117      return false;
118    }
119    return true;
120  }
121
122  /**
123  * This function is used to register a variable to be synchronized
124  * also counts the total datasize needed to save the variables
125  * @param var pointer to the variable
126  * @param size size of the datatype the variable consists of
127  */
128  void Synchronisable::registerVar(void *var, int size, variableType t, int mode, NetworkCallbackBase *cb){
129    // create temporary synch.Var struct
130    synchronisableVariable *temp = new synchronisableVariable;
131    temp->size = size;
132    temp->var = var;
133    temp->mode = mode;
134    temp->type = t;
135    temp->callback = cb;
136    COUT(5) << "Syncronisable::registering var with size: " << temp->size << " and type: " << temp->type << std::endl;
137    // increase datasize
138    datasize+=sizeof(int)+size;
139    //std::cout << "push temp to syncList (at the bottom) " << datasize << std::endl;
140    COUT(5) << "Syncronisable::objectID: " << objectID << " this: " << this << " name: " << this->getIdentifier()->getName() << " networkID: " << this->getIdentifier()->getNetworkID() << std::endl;
141    syncList->push_back(temp);
142  }
143
144
145  /**
146  * This function takes all SynchronisableVariables out of the Synchronisable and saves it into a syncData struct
147  * Difference to the above function:
148  * takes a pointer to already allocated memory (must have at least getSize bytes length)
149  * structure of the bitstream:
150  * (var1_size,var1,var2_size,var2,...)
151  * varx_size: size = sizeof(int)
152  * varx: size = varx_size
153  * @return data containing all variables and their sizes
154  */
155  syncData Synchronisable::getData(unsigned char *mem, int mode){
156    //std::cout << "inside getData" << std::endl;
157    if(mode==0x0)
158      mode=state_;
159    if(classID==0)
160      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
161    this->classID=this->getIdentifier()->getNetworkID();
162    std::list<synchronisableVariable *>::iterator i;
163    syncData retVal;
164    retVal.objectID=this->objectID;
165    retVal.classID=this->classID;
166    retVal.length=getSize();
167    COUT(5) << "Synchronisable getting data from objectID: " << retVal.objectID << " classID: " << retVal.classID << " length: " << retVal.length << std::endl;
168    retVal.data=mem;
169    // copy to location
170    int n=0; //offset
171    for(i=syncList->begin(); n<datasize && i!=syncList->end(); ++i){
172      //(std::memcpy(retVal.data+n, (const void*)(&(i->size)), sizeof(int));
173      if( ((*i)->mode & mode) == 0 ){
174        COUT(5) << "not getting data: " << std::endl;
175        continue;  // this variable should only be received
176      }
177      switch((*i)->type){
178      case DATA:
179        memcpy( (void *)(retVal.data+n), (void*)((*i)->var), (*i)->size);
180        n+=(*i)->size;
181        break;
182      case STRING:
183        memcpy( (void *)(retVal.data+n), (void *)&((*i)->size), sizeof(int) );
184        n+=sizeof(int);
185        const char *data = ( ( *(std::string *) (*i)->var).c_str());
186        memcpy( retVal.data+n, (void*)data, (*i)->size);
187        COUT(5) << "synchronisable: char: " << (const char *)(retVal.data+n) << " data: " << data << " string: " << *(std::string *)((*i)->var) << std::endl;
188        n+=(*i)->size;
189        break;
190      }
191    }
192    return retVal;
193  }
194 
195  /**
196   * This function takes all SynchronisableVariables out of the Synchronisable and saves it into a syncData struct
197  * Difference to the above function:
198   * takes a pointer to already allocated memory (must have at least getSize bytes length)
199  * structure of the bitstream:
200   * (var1_size,var1,var2_size,var2,...)
201   * varx_size: size = sizeof(int)
202   * varx: size = varx_size
203   * @return data containing all variables and their sizes
204   */
205  bool Synchronisable::getData2(unsigned char*& mem, int mode){
206    //std::cout << "inside getData" << std::endl;
207    unsigned int tempsize = 0;
208    if(mode==0x0)
209      mode=state_;
210    if(classID==0)
211      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
212    this->classID=this->getIdentifier()->getNetworkID();
213    std::list<synchronisableVariable *>::iterator i;
214    unsigned int size;
215    size=getSize2(mode);
216   
217    // start copy header
218    memcpy(mem, &size, sizeof(unsigned int));
219    mem+=sizeof(unsigned int);
220    memcpy(mem, &(this->objectID), sizeof(unsigned int));
221    mem+=sizeof(unsigned int);
222    memcpy(mem, &(this->classID), sizeof(unsigned int));
223    mem+=sizeof(unsigned int);
224    tempsize+=12;
225    // end copy header
226   
227    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << " length: " << size << std::endl;
228    // copy to location
229    for(i=syncList->begin(); i!=syncList->end(); ++i){
230      //(std::memcpy(retVal.data+n, (const void*)(&(i->size)), sizeof(int));
231      if( ((*i)->mode & mode) == 0 ){
232        COUT(5) << "not getting data: " << std::endl;
233        continue;  // this variable should only be received
234      }
235      switch((*i)->type){
236        case DATA:
237          memcpy( (void *)(mem), (void*)((*i)->var), (*i)->size);
238          mem+=(*i)->size;
239          tempsize+=(*i)->size;
240          break;
241        case STRING:
242          memcpy( (void *)(mem), (void *)&((*i)->size), sizeof(int) );
243          mem+=sizeof(int);
244          const char *data = ( ( *(std::string *) (*i)->var).c_str());
245          memcpy( mem, (void*)data, (*i)->size);
246          COUT(5) << "synchronisable: char: " << (const char *)(mem) << " data: " << data << " string: " << *(std::string *)((*i)->var) << std::endl;
247          mem+=(*i)->size;
248          tempsize+=(*i)->size + 4;
249          break;
250      }
251    }
252    assert(tempsize==size);
253    return true;
254  }
255
256  /*bool Synchronisable::getData(Bytestream& bs, int mode)
257  {
258    //std::cout << "inside getData" << std::endl;
259    if(mode==0x0)
260      mode=state_;
261    if(classID==0)
262      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
263    this->classID=this->getIdentifier()->getNetworkID();
264    std::list<synchronisableVariable *>::iterator i;
265    bs << this->getSize();
266    bs << this->objectID;
267    bs << this->classID;
268    // copy to location
269    for(i=syncList->begin(); i!=syncList->end(); ++i){
270      if( ((*i)->mode & mode) == 0 ){
271        COUT(5) << "not getting data: " << std::endl;
272        continue;  // this variable should only be received
273      }
274      switch((*i)->type){
275        case DATA:
276          bs << *(*i)->var;
277          //std::memcpy( (void *)(retVal.data+n), (void*)((*i)->var), (*i)->size);
278          //n+=(*i)->size;
279          break;
280        case STRING:
281          bs << *(String *)((*i)->var);
282          //memcpy( (void *)(retVal.data+n), (void *)&((*i)->size), sizeof(int) );
283          //n+=sizeof(int);
284          //const char *data = ( ( *(std::string *) (*i)->var).c_str());
285          //std::memcpy( retVal.data+n, (void*)data, (*i)->size);
286          //COUT(5) << "synchronisable: char: " << (const char *)(retVal.data+n) << " data: " << data << " string: " << *(std::string *)((*i)->var) << std::endl;
287          //n+=(*i)->size;
288          break;
289      }
290    }
291    return true;
292  }*/
293
294 
295  /**
296  * This function takes a syncData struct and takes it to update the variables
297  * @param vars data of the variables
298  * @return true/false
299  */
300  bool Synchronisable::updateData(syncData vars, int mode){
301    if(mode==0x0)
302      mode=state_;
303    unsigned char *data=vars.data;
304    std::list<synchronisableVariable *>::iterator i;
305    if(syncList->empty()){
306      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
307      return false;
308    }
309    COUT(5) << "Synchronisable: objectID " << vars.objectID << ", classID " << vars.classID << " size: " << vars.length << " synchronising data" << std::endl;
310    for(i=syncList->begin(); i!=syncList->end(); i++){
311      if( ((*i)->mode ^ mode) == 0 ){
312        COUT(5) << "synchronisable: not updating variable " << std::endl;
313        continue;  // this variable should only be set
314      }
315      COUT(5) << "Synchronisable: element size: " << (*i)->size << " type: " << (*i)->type << std::endl;
316      bool callback=false;
317      switch((*i)->type){
318      case DATA:
319        if((*i)->callback) // check whether this variable changed (but only if callback was set)
320          if(strncmp((char *)(*i)->var, (char *)data, (*i)->size)!=0)
321            callback=true;
322        memcpy((void*)(*i)->var, data, (*i)->size);
323        data+=(*i)->size;
324        break;
325      case STRING:
326        (*i)->size = *(int *)data;
327        COUT(5) << "string size: " << (*i)->size << std::endl;
328        data+=sizeof(int);
329        if((*i)->callback) // check whether this string changed
330          if( *(std::string *)((*i)->var) != std::string((char *)data) )
331            callback=true;
332        *((std::string *)((*i)->var)) = std::string((const char*)data);
333        COUT(5) << "synchronisable: char: " << (const char*)data << " string: " << std::string((const char*)data) << std::endl;
334        data += (*i)->size;
335        break;
336      }
337      // call the callback function, if defined
338      if(callback && (*i)->callback)
339        (*i)->callback->call();
340    }
341    return true;
342  }
343 
344  /**
345   * This function takes a syncData struct and takes it to update the variables
346   * @param vars data of the variables
347   * @return true/false
348   */
349  bool Synchronisable::updateData(unsigned char*& mem, int mode){
350    unsigned char *data = mem;
351    if(mode==0x0)
352      mode=state_;
353    std::list<synchronisableVariable *>::iterator i;
354    if(syncList->empty()){
355      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
356      return false;
357    }
358   
359    // start extract header
360    unsigned int objectID, classID, size;
361    size = *(int *)mem;
362    mem+=sizeof(size);
363    objectID = *(int *)mem;
364    mem+=sizeof(objectID);
365    classID = *(int *)mem;
366    mem+=sizeof(classID);
367    // stop extract header
368    assert(this->objectID==objectID);
369    assert(this->classID==classID);
370   
371    COUT(5) << "Synchronisable: objectID " << objectID << ", classID " << classID << " size: " << size << " synchronising data" << std::endl;
372    for(i=syncList->begin(); i!=syncList->end() && mem <= data+size; i++){
373      if( ((*i)->mode ^ mode) == 0 ){
374        COUT(5) << "synchronisable: not updating variable " << std::endl;
375        continue;  // this variable should only be set
376      }
377      COUT(5) << "Synchronisable: element size: " << (*i)->size << " type: " << (*i)->type << std::endl;
378      bool callback=false;
379      switch((*i)->type){
380        case DATA:
381          if((*i)->callback) // check whether this variable changed (but only if callback was set)
382            if(strncmp((char *)(*i)->var, (char *)mem, (*i)->size)!=0)
383              callback=true;
384          memcpy((void*)(*i)->var, mem, (*i)->size);
385          mem+=(*i)->size;
386          break;
387        case STRING:
388          (*i)->size = *(int *)mem;
389          COUT(5) << "string size: " << (*i)->size << std::endl;
390          mem+=sizeof(int);
391          if((*i)->callback) // check whether this string changed
392            if( *(std::string *)((*i)->var) != std::string((char *)mem) )
393              callback=true;
394          *((std::string *)((*i)->var)) = std::string((const char*)mem);
395          COUT(5) << "synchronisable: char: " << (const char*)mem << " string: " << std::string((const char*)mem) << std::endl;
396          mem += (*i)->size;
397          break;
398      }
399      // call the callback function, if defined
400      if(callback && (*i)->callback)
401        (*i)->callback->call();
402    }
403    return true;
404  }
405
406  /**
407  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
408  * @return amount of bytes
409  */
410  int Synchronisable::getSize(int mode){
411    int tsize=0;
412    if(mode==0x0)
413      mode=state_;
414    std::list<synchronisableVariable *>::iterator i;
415    for(i=syncList->begin(); i!=syncList->end(); i++){
416      if( ((*i)->mode & mode) == 0 )
417        continue;  // this variable should only be received, so dont add its size to the send-size
418      switch((*i)->type){
419      case DATA:
420        tsize+=(*i)->size;
421        break;
422      case STRING:
423        tsize+=sizeof(int);
424        (*i)->size=((std::string *)(*i)->var)->length()+1;
425        COUT(5) << "String size: " << (*i)->size << std::endl;
426        tsize+=(*i)->size;
427        break;
428      }
429    }
430    return tsize;
431  }
432
433  /**
434   * This function returns the total amount of bytes needed by getData to save the whole content of the variables
435   * @return amount of bytes
436   */
437  int Synchronisable::getSize2(int mode){
438    return 3*sizeof(unsigned int) + getSize( mode );
439  }
440 
441  bool Synchronisable::isMyData(unsigned char* mem)
442  {
443    unsigned int objectID, classID, size;
444    size = *(int *)mem;
445    mem+=sizeof(size);
446    objectID = *(int *)mem;
447    mem+=sizeof(objectID);
448    classID = *(int *)mem;
449    mem+=sizeof(classID);
450   
451    assert(classID == this->classID);
452    return (objectID == this->objectID);
453  }
454 
455  void Synchronisable::setBacksync(bool sync){
456    backsync_=sync;
457  }
458
459  bool Synchronisable::getBacksync(){
460    return backsync_;
461  }
462
463}
Note: See TracBrowser for help on using the repository browser.