Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/network/Synchronisable.cc @ 1740

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

network branch merged into trunk

  • 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      return false; // most probably the gamestate is corrupted
101    }
102    orxonox::BaseObject *bo = id->fabricate();
103    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
104    assert(no);
105    no->objectID=objectID;
106    no->classID=classID;
107    COUT(3) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
108          // update data and create object/entity...
109    if( !no->updateData(mem, mode) ){
110      COUT(1) << "We couldn't update the object: " << objectID << std::endl;
111      return false;
112    }
113    if( !no->create() )
114    {
115      COUT(1) << "We couldn't manifest (create() ) the object: " << objectID << std::endl;
116      return false;
117    }
118    return true;
119  }
120
121  /**
122  * This function is used to register a variable to be synchronized
123  * also counts the total datasize needed to save the variables
124  * @param var pointer to the variable
125  * @param size size of the datatype the variable consists of
126  */
127  void Synchronisable::registerVar(void *var, int size, variableType t, int mode, NetworkCallbackBase *cb){
128    // create temporary synch.Var struct
129    synchronisableVariable *temp = new synchronisableVariable;
130    temp->size = size;
131    temp->var = var;
132    temp->mode = mode;
133    temp->type = t;
134    temp->callback = cb;
135    COUT(5) << "Syncronisable::registering var with size: " << temp->size << " and type: " << temp->type << std::endl;
136    // increase datasize
137    datasize+=sizeof(int)+size;
138    //std::cout << "push temp to syncList (at the bottom) " << datasize << std::endl;
139    COUT(5) << "Syncronisable::objectID: " << objectID << " this: " << this << " name: " << this->getIdentifier()->getName() << " networkID: " << this->getIdentifier()->getNetworkID() << std::endl;
140    syncList->push_back(temp);
141  }
142
143
144  /**
145  * This function takes all SynchronisableVariables out of the Synchronisable and saves it into a syncData struct
146  * Difference to the above function:
147  * takes a pointer to already allocated memory (must have at least getSize bytes length)
148  * structure of the bitstream:
149  * (var1_size,var1,var2_size,var2,...)
150  * varx_size: size = sizeof(int)
151  * varx: size = varx_size
152  * @return data containing all variables and their sizes
153  */
154  syncData Synchronisable::getData(unsigned char *mem, int mode){
155    //std::cout << "inside getData" << std::endl;
156    if(mode==0x0)
157      mode=state_;
158    if(classID==0)
159      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
160    this->classID=this->getIdentifier()->getNetworkID();
161    std::list<synchronisableVariable *>::iterator i;
162    syncData retVal;
163    retVal.objectID=this->objectID;
164    retVal.classID=this->classID;
165    retVal.length=getSize();
166    COUT(5) << "Synchronisable getting data from objectID: " << retVal.objectID << " classID: " << retVal.classID << " length: " << retVal.length << std::endl;
167    retVal.data=mem;
168    // copy to location
169    int n=0; //offset
170    for(i=syncList->begin(); n<datasize && i!=syncList->end(); ++i){
171      //(std::memcpy(retVal.data+n, (const void*)(&(i->size)), sizeof(int));
172      if( ((*i)->mode & mode) == 0 ){
173        COUT(5) << "not getting data: " << std::endl;
174        continue;  // this variable should only be received
175      }
176      switch((*i)->type){
177      case DATA:
178        memcpy( (void *)(retVal.data+n), (void*)((*i)->var), (*i)->size);
179        n+=(*i)->size;
180        break;
181      case STRING:
182        memcpy( (void *)(retVal.data+n), (void *)&((*i)->size), sizeof(int) );
183        n+=sizeof(int);
184        const char *data = ( ( *(std::string *) (*i)->var).c_str());
185        memcpy( retVal.data+n, (void*)data, (*i)->size);
186        COUT(5) << "synchronisable: char: " << (const char *)(retVal.data+n) << " data: " << data << " string: " << *(std::string *)((*i)->var) << std::endl;
187        n+=(*i)->size;
188        break;
189      }
190    }
191    return retVal;
192  }
193 
194  /**
195   * This function takes all SynchronisableVariables out of the Synchronisable and saves it into a syncData struct
196  * Difference to the above function:
197   * takes a pointer to already allocated memory (must have at least getSize bytes length)
198  * structure of the bitstream:
199   * (var1_size,var1,var2_size,var2,...)
200   * varx_size: size = sizeof(int)
201   * varx: size = varx_size
202   * @return data containing all variables and their sizes
203   */
204  bool Synchronisable::getData2(unsigned char*& mem, int mode){
205    //std::cout << "inside getData" << std::endl;
206    unsigned int tempsize = 0;
207    if(mode==0x0)
208      mode=state_;
209    if(classID==0)
210      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
211    this->classID=this->getIdentifier()->getNetworkID();
212    std::list<synchronisableVariable *>::iterator i;
213    unsigned int size;
214    size=getSize2(mode);
215   
216    // start copy header
217    memcpy(mem, &size, sizeof(unsigned int));
218    mem+=sizeof(unsigned int);
219    memcpy(mem, &(this->objectID), sizeof(unsigned int));
220    mem+=sizeof(unsigned int);
221    memcpy(mem, &(this->classID), sizeof(unsigned int));
222    mem+=sizeof(unsigned int);
223    tempsize+=12;
224    // end copy header
225   
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.