Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/network/Synchronisable.cc @ 2028

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

updated updateMedia script
updated TODO file
we are able to synchronise the creatorID of an object now

  • Property svn:eol-style set to native
File size: 17.7 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 <cstring>
44#include <string>
45#include <iostream>
46#include <assert.h>
47
48#include "core/CoreIncludes.h"
49#include "core/BaseObject.h"
50// #include "core/Identifier.h"
51
52namespace network
53{
54
55
56  std::map<unsigned int, Synchronisable *> Synchronisable::objectMap_;
57  std::queue<unsigned int> Synchronisable::deletedObjects_;
58
59  int Synchronisable::state_=0x1; // detemines wheter we are server (default) or client
60
61  /**
62  * Constructor:
63  * Initializes all Variables and sets the right objectID
64  */
65  Synchronisable::Synchronisable(){
66    RegisterRootObject(Synchronisable);
67    static uint32_t idCounter=0;
68    objectFrequency_=1;
69    objectMode_=0x1; // by default do not send data to server
70    objectID=idCounter++;
71    classID = (unsigned int)-1;
72    syncList = new std::list<synchronisableVariable *>;
73  }
74
75  /**
76   * Destructor:
77   * Delete all callback objects and remove objectID from the objectMap_
78   */
79  Synchronisable::~Synchronisable(){
80    // delete callback function objects
81    if(!orxonox::Identifier::isCreatingHierarchy()){
82      for(std::list<synchronisableVariable *>::iterator it = syncList->begin(); it!=syncList->end(); it++)
83        delete (*it)->callback;
84      if (this->objectMode_ != 0x0)
85        deletedObjects_.push(objectID);
86//       COUT(3) << "destruct synchronisable +++" << objectID << " | " << classID << std::endl;
87//       COUT(3) << " bump ---" << objectID << " | " << &objectMap_ << std::endl;
88//       assert(objectMap_[objectID]->objectID==objectID);
89//       objectMap_.erase(objectID);
90    }
91  }
92
93  /**
94   * This function gets called after all neccessary data has been passed to the object
95   * Overload this function and recall the create function of the parent class
96   * @return true/false
97   */
98  bool Synchronisable::create(){
99    this->classID = this->getIdentifier()->getNetworkID();
100//     COUT(4) << "creating synchronisable: setting classid from " << this->getIdentifier()->getName() << " to: " << classID << std::endl;
101
102//     COUT(3) << "construct synchronisable +++" << objectID << " | " << classID << std::endl;
103//     objectMap_[objectID]=this;
104//     assert(objectMap_[objectID]==this);
105//     assert(objectMap_[objectID]->objectID==objectID);
106    return true;
107  }
108
109
110  /**
111   * This function sets the internal mode for synchronisation
112   * @param b true if this object is located on a client or on a server
113   */
114  void Synchronisable::setClient(bool b){
115    if(b) // client
116      state_=0x2;
117    else  // server
118      state_=0x1;
119  }
120
121  /**
122   * This function fabricated a new synchrnisable (and children of it), sets calls updateData and create
123   * After calling this function the mem pointer will be increased by the size of the needed data
124   * @param mem pointer to where the appropriate data is located
125   * @param mode defines the mode, how the data should be loaded
126   * @return pointer to the newly created synchronisable
127   */
128  Synchronisable *Synchronisable::fabricate(uint8_t*& mem, int mode)
129  {
130    synchronisableHeader *header = (synchronisableHeader *)mem;
131
132    COUT(3) << "fabricating object with id: " << header->objectID << std::endl;
133
134    orxonox::Identifier* id = ClassByID(header->classID);
135    assert(id);
136    orxonox::BaseObject *bo = id->fabricate(0); //TODO: get BaseObject* from header->creatorID here
137    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
138    assert(no);
139    no->objectID=header->objectID;
140    no->classID=header->classID;
141    COUT(3) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
142          // update data and create object/entity...
143    bool b = no->updateData(mem, mode, true);
144    assert(b);
145    b = no->create();
146    assert(b);
147    return no;
148  }
149
150
151  /**
152   * Finds and deletes the Synchronisable with the appropriate objectID
153   * @param objectID objectID of the Synchronisable
154   * @return true/false
155   */
156  bool Synchronisable::deleteObject(unsigned int objectID){
157//     assert(getSynchronisable(objectID));
158    if(!getSynchronisable(objectID))
159      return false;
160    assert(getSynchronisable(objectID)->objectID==objectID);
161//     delete objectMap_[objectID];
162    Synchronisable *s = getSynchronisable(objectID);
163    if(s)
164      delete s;
165    else
166      return false;
167    return true;
168  }
169
170  /**
171   * This function looks up the objectID in the objectMap_ and returns a pointer to the right Synchronisable
172   * @param objectID objectID of the Synchronisable
173   * @return pointer to the Synchronisable with the objectID
174   */
175  Synchronisable* Synchronisable::getSynchronisable(unsigned int objectID){
176    orxonox::ObjectList<Synchronisable>::iterator it;
177    for(it = orxonox::ObjectList<Synchronisable>::begin(); it; ++it){
178      if( it->getObjectID()==objectID )
179           return *it;
180    }
181    return NULL;
182
183//     std::map<unsigned int, Synchronisable *>::iterator i = objectMap_.find(objectID);
184//     if(i==objectMap_.end())
185//       return NULL;
186//     assert(i->second->objectID==objectID);
187//     return (*i).second;
188  }
189
190
191  /**
192  * This function is used to register a variable to be synchronized
193  * also counts the total datasize needed to save the variables
194  * @param var pointer to the variable
195  * @param size size of the datatype the variable consists of
196  * @param t the type of the variable (network::DATA or network::STRING
197  * @param mode same as in getData
198  * @param cb callback object that should get called, if the value of the variable changes
199  */
200  void Synchronisable::registerVar(void *var, int size, variableType t, int mode, NetworkCallbackBase *cb){
201    assert( mode==direction::toclient || mode==direction::toserver || mode==direction::serverMaster || mode==direction::clientMaster);
202    // create temporary synch.Var struct
203    synchronisableVariable *temp = new synchronisableVariable;
204    temp->size = size;
205    temp->var = var;
206    temp->mode = mode;
207    temp->type = t;
208    temp->callback = cb;
209    if( ( mode & direction::bidirectional ) )
210    {
211      temp->varBuffer = new uint8_t[size];
212      memcpy(temp->varBuffer, temp->var, size); //now fill the buffer for the first time
213      temp->varReference = 0;
214    }
215    COUT(5) << "Syncronisable::registering var with size: " << temp->size << " and type: " << temp->type << std::endl;
216    //std::cout << "push temp to syncList (at the bottom) " << datasize << std::endl;
217    COUT(5) << "Syncronisable::objectID: " << objectID << " this: " << this << " name: " << this->getIdentifier()->getName() << " networkID: " << this->getIdentifier()->getNetworkID() << std::endl;
218    syncList->push_back(temp);
219#ifndef NDEBUG
220    std::list<synchronisableVariable *>::iterator it = syncList->begin();
221    while(it!=syncList->end()){
222      assert(*it!=var);
223      it++;
224    }
225#endif
226  }
227
228  /**
229   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID and classID to the given memory
230   * takes a pointer to already allocated memory (must have at least getSize bytes length)
231   * structure of the bitstream:
232   * |totalsize,objectID,classID,var1,var2,string1_length,string1,var3,...|
233   * length of varx: size saved int syncvarlist
234   * @param mem pointer to allocated memory with enough size
235   * @param id gamestateid of the gamestate to be saved (important for priorities)
236   * @param mode defines the direction in which the data will be send/received
237   *             0x1: server->client
238   *             0x2: client->server (not recommended)
239   *             0x3: bidirectional
240   * @return true: if !doSync or if everything was successfully saved
241   */
242  bool Synchronisable::getData(uint8_t*& mem, unsigned int id, int mode){
243    //if this tick is we dont synchronise, then abort now
244    if(!doSync(id))
245      return true;
246    //std::cout << "inside getData" << std::endl;
247    unsigned int tempsize = 0;
248    if(mode==0x0)
249      mode=state_;
250    if(classID==0)
251      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
252
253    if (this->classID == (unsigned int)-1)
254        this->classID = this->getIdentifier()->getNetworkID();
255
256    assert(this->classID==this->getIdentifier()->getNetworkID());
257//     this->classID=this->getIdentifier()->getNetworkID(); // TODO: correct this
258    std::list<synchronisableVariable *>::iterator i;
259    unsigned int size;
260    size=getSize(id, mode);
261
262    // start copy header
263    synchronisableHeader *header = (synchronisableHeader *)mem;
264    header->size = size;
265    header->objectID = this->objectID;
266    header->creatorID = this->creatorID;
267    header->classID = this->classID;
268    header->dataAvailable = true;
269    tempsize+=sizeof(synchronisableHeader);
270    mem+=sizeof(synchronisableHeader);
271    // end copy header
272
273
274    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << " length: " << size << std::endl;
275    // copy to location
276    for(i=syncList->begin(); i!=syncList->end(); ++i){
277      if( ((*i)->mode & mode) == 0 ){
278        COUT(5) << "not getting data: " << std::endl;
279        continue;  // this variable should only be received
280      }
281      // if the variable gets synchronised bidirectional, then add the reference to the bytestream
282      if( ( (*i)->mode & direction::bidirectional ) )
283      {
284        *(uint8_t*)mem = (*i)->varReference;
285        mem += sizeof( (*i)->varReference );
286      }
287      switch((*i)->type){
288        case DATA:
289          memcpy( (void *)(mem), (void*)((*i)->var), (*i)->size);
290          mem+=(*i)->size;
291          tempsize+=(*i)->size + sizeof( (*i)->varReference );
292          break;
293        case STRING:
294          memcpy( (void *)(mem), (void *)&((*i)->size), sizeof(size_t) );
295          mem+=sizeof(size_t);
296          const char *data = ( ( *(std::string *) (*i)->var).c_str());
297          memcpy( mem, (void*)data, (*i)->size);
298          COUT(5) << "synchronisable: char: " << (const char *)(mem) << " data: " << data << " string: " << *(std::string *)((*i)->var) << std::endl;
299          mem+=(*i)->size;
300          tempsize+=(*i)->size + sizeof( (*i)->varReference ) + sizeof(size_t);
301          break;
302      }
303    }
304    assert(tempsize==size);
305    return true;
306  }
307
308
309  /**
310   * This function takes a bytestream and loads the data into the registered variables
311   * @param mem pointer to the bytestream
312   * @param mode same as in getData
313   * @return true/false
314   */
315  bool Synchronisable::updateData(uint8_t*& mem, int mode, bool forceCallback){
316    if(mode==0x0)
317      mode=state_;
318    std::list<synchronisableVariable *>::iterator i;
319    if(syncList->empty()){
320      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
321      return false;
322    }
323
324    uint8_t *data=mem;
325    // start extract header
326    synchronisableHeader *syncHeader = (synchronisableHeader *)mem;
327    assert(syncHeader->objectID==this->objectID);
328    assert(syncHeader->creatorID==this->creatorID);
329    if(syncHeader->dataAvailable==false){
330      mem+=syncHeader->size;
331      return true;
332    }
333
334    mem+=sizeof(synchronisableHeader);
335    // stop extract header
336    assert(this->objectID==syncHeader->objectID);
337//    assert(this->classID==syncHeader->classID); //TODO: fix this!!! maybe a problem with the identifier ?
338
339    COUT(5) << "Synchronisable: objectID " << syncHeader->objectID << ", classID " << syncHeader->classID << " size: " << syncHeader->size << " synchronising data" << std::endl;
340    for(i=syncList->begin(); i!=syncList->end() && mem <= data+syncHeader->size; i++){
341      if( ((*i)->mode ^ mode) == 0 ){
342        COUT(5) << "synchronisable: not updating variable " << std::endl;
343        continue;  // this variable should only be set
344      }
345      COUT(5) << "Synchronisable: element size: " << (*i)->size << " type: " << (*i)->type << std::endl;
346      bool callback=false;
347      switch((*i)->type){
348        case DATA:
349          if( ( (*i)->mode & direction::bidirectional ) )
350          {
351            if( ( mode == 0x1 && (*i)->mode == direction::serverMaster ) || \
352                  ( mode == 0x2 && (*i)->mode == direction::clientMaster ) )    // if true we are master on this variable
353            {
354              uint8_t refNr = *(uint8_t *)mem;
355              if( refNr != (*i)->varReference )
356              {
357                mem += sizeof((*i)->varReference) + (*i)->size; // the reference for this variable is not recent, discard data
358                break;
359              }
360            }
361            else //we are slave for this variable
362            {
363              (*i)->varReference = *(uint8_t *)mem; //copy the reference value for this variable
364            }
365            mem += sizeof((*i)->varReference);
366          }
367          if((*i)->callback) // check whether this variable changed (but only if callback was set)
368            if(strncmp((char *)(*i)->var, (char *)mem, (*i)->size)!=0)
369              callback=true;
370          memcpy((void*)(*i)->var, mem, (*i)->size);
371          mem+=(*i)->size;
372          break;
373        case STRING:
374          if( ( (*i)->mode & direction::bidirectional ) )
375          {
376            if( ( mode == 0x1 && (*i)->mode == direction::serverMaster ) || \
377                  ( mode == 0x2 && (*i)->mode == direction::clientMaster ) )    // if true we are master for this variable
378            {
379              uint8_t refNr = *(uint8_t *)mem;
380              mem += sizeof( (*i)->varReference );
381              if( refNr != (*i)->varReference ){
382                mem += sizeof(size_t) + *(size_t *)mem; // the reference for this variable is not recent, discard data
383                break;
384              }
385            }
386            else //we are slave for this variable
387            {
388              (*i)->varReference = *(uint8_t *)mem; //copy the reference value for this variable
389            }
390            mem += sizeof( (*i)->varReference );
391          }
392          (*i)->size = *(size_t *)mem;
393          COUT(5) << "string size: " << (*i)->size << std::endl;
394          mem += sizeof(size_t);
395          if((*i)->callback) // check whether this string changed
396            if( *(std::string *)((*i)->var) != std::string((char *)mem) )
397              callback=true;
398          *((std::string *)((*i)->var)) = std::string((const char*)mem);
399          COUT(5) << "synchronisable: char: " << (const char*)mem << " string: " << std::string((const char*)mem) << std::endl;
400          mem += (*i)->size;
401          break;
402      }
403      // call the callback function, if defined
404      if((callback || forceCallback) && (*i)->callback)
405        (*i)->callback->call();
406    }
407    return true;
408  }
409
410  /**
411  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
412  * @param id id of the gamestate
413  * @param mode same as getData
414  * @return amount of bytes
415  */
416  uint32_t Synchronisable::getSize(unsigned int id, int mode){
417    if(!doSync(id))
418      return 0;
419    int tsize=sizeof(synchronisableHeader);
420    if(mode==0x0)
421      mode=state_;
422    std::list<synchronisableVariable *>::iterator i;
423    for(i=syncList->begin(); i!=syncList->end(); i++){
424      if( ((*i)->mode & mode) == 0 )
425        continue;  // this variable should only be received, so dont add its size to the send-size
426      switch((*i)->type){
427      case DATA:
428        tsize+=(*i)->size;
429        break;
430      case STRING:
431        tsize+=sizeof(int);
432        (*i)->size=((std::string *)(*i)->var)->length()+1;
433        COUT(5) << "String size: " << (*i)->size << std::endl;
434        tsize+=(*i)->size;
435        break;
436      }
437      if( ( (*i)->mode & direction::bidirectional ) != 0)
438      {
439        tsize+=sizeof( (*i)->varReference );
440      }
441    }
442    return tsize;
443  }
444
445  /**
446   * This function determines, wheter the object should be saved to the bytestream (according to its syncmode/direction)
447   * @param id gamestate id
448   * @return true/false
449   */
450  bool Synchronisable::doSync(unsigned int id){
451    return ( (objectMode_&state_)!=0 );
452  }
453
454  bool Synchronisable::doSelection(unsigned int id){
455    return ( id==0 || id%objectFrequency_==objectID%objectFrequency_ ) && ((objectMode_&state_)!=0);
456  }
457
458  /**
459   * This function looks at the header located in the bytestream and checks wheter objectID and classID match with the Synchronisables ones
460   * @param mem pointer to the bytestream
461   */
462  bool Synchronisable::isMyData(uint8_t* mem)
463  {
464    synchronisableHeader *header = (synchronisableHeader *)mem;
465    assert(header->objectID==this->objectID);
466    return header->dataAvailable;
467  }
468
469  /**
470   * This function sets the synchronisation mode of the object
471   * If set to 0x1 variables will only be synchronised to the client
472   * If set to 0x2 variables will only be synchronised to the server
473   * If set to 0x3 variables will be synchronised bidirectionally (only if set so in registerVar)
474   * @param mode same as in registerVar
475   */
476  void Synchronisable::setObjectMode(int mode){
477    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
478    objectMode_=mode;
479  }
480
481
482}
Note: See TracBrowser for help on using the repository browser.