Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2168 was 2168, checked in by landauf, 15 years ago

Split up LevelManager into LevelManager and PlayerManager where LevelManager handles all levels and is only active on the server, while PlayerManager handles client connections and passes new players to the LevelManager (if running on a server). If running on a client, PlayerManager just maps PlayerInfos with clientIDs.

Also added a small hack in Level.cc to show the ChatOverlay on clients.

  • Property svn:eol-style set to native
File size: 22.1 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
52#include "Host.h"
53namespace orxonox
54{
55
56
57  std::map<unsigned int, Synchronisable *> Synchronisable::objectMap_;
58  std::queue<unsigned int> Synchronisable::deletedObjects_;
59
60  uint8_t Synchronisable::state_=0x1; // detemines wheter we are server (default) or client
61
62  /**
63  * Constructor:
64  * Initializes all Variables and sets the right objectID
65  */
66  Synchronisable::Synchronisable(BaseObject* creator){
67    RegisterRootObject(Synchronisable);
68    static uint32_t idCounter=0;
69    objectFrequency_=1;
70    objectMode_=0x1; // by default do not send data to server
71    if ( !Host::running() || ( Host::running() && Host::isServer() ) )
72    {
73      this->objectID = idCounter++; //this is only needed when running a server
74    //add synchronisable to the objectMap
75      objectMap_[this->objectID] = this;
76    }
77    else
78      objectID=OBJECTID_UNKNOWN;
79    classID = (unsigned int)-1;
80    syncList = new std::list<synchronisableVariable *>;
81
82
83#ifndef NDEBUG
84    ObjectList<Synchronisable>::iterator it;
85    for(it = ObjectList<Synchronisable>::begin(); it!=ObjectList<Synchronisable>::end(); ++it){
86      if( it->getObjectID()==this->objectID )
87        assert(*it==this || (it->objectID==OBJECTID_UNKNOWN && it->objectMode_==0x0));
88    }
89#endif
90
91    this->creatorID = OBJECTID_UNKNOWN;
92
93    searchcreatorID:
94    if (creator)
95    {
96        Synchronisable* synchronisable_creator = dynamic_cast<Synchronisable*>(creator);
97        if (synchronisable_creator && synchronisable_creator->objectMode_)
98        {
99            this->creatorID = synchronisable_creator->getObjectID();
100        }
101        else if (creator != creator->getCreator())
102        {
103            creator = creator->getCreator();
104            goto searchcreatorID;
105        }
106    }
107  }
108
109  /**
110   * Destructor:
111   * Delete all callback objects and remove objectID from the objectMap_
112   */
113  Synchronisable::~Synchronisable(){
114    // delete callback function objects
115    if(!Identifier::isCreatingHierarchy()){
116      for(std::list<synchronisableVariable *>::iterator it = syncList->begin(); it!=syncList->end(); it++)
117        delete (*it)->callback;
118      if (this->objectMode_ != 0x0 && (Host::running() && Host::isServer()))
119        deletedObjects_.push(objectID);
120//       COUT(3) << "destruct synchronisable +++" << objectID << " | " << classID << std::endl;
121//       COUT(3) << " bump ---" << objectID << " | " << &objectMap_ << std::endl;
122//       assert(objectMap_[objectID]->objectID==objectID);
123//       objectMap_.erase(objectID);
124    }
125    std::map<unsigned int, Synchronisable*>::iterator it;
126    it = objectMap_.find(objectID);
127    if (it != objectMap_.end())
128      objectMap_.erase(it);
129  }
130
131  /**
132   * This function gets called after all neccessary data has been passed to the object
133   * Overload this function and recall the create function of the parent class
134   * @return true/false
135   */
136  bool Synchronisable::create(){
137    this->classID = this->getIdentifier()->getNetworkID();
138//     COUT(4) << "creating synchronisable: setting classid from " << this->getIdentifier()->getName() << " to: " << classID << std::endl;
139
140//     COUT(3) << "construct synchronisable +++" << objectID << " | " << classID << std::endl;
141//     objectMap_[objectID]=this;
142//     assert(objectMap_[objectID]==this);
143//     assert(objectMap_[objectID]->objectID==objectID);
144    return true;
145  }
146
147
148  /**
149   * This function sets the internal mode for synchronisation
150   * @param b true if this object is located on a client or on a server
151   */
152  void Synchronisable::setClient(bool b){
153    if(b) // client
154      state_=0x2;
155    else  // server
156      state_=0x1;
157  }
158
159  /**
160   * This function fabricated a new synchrnisable (and children of it), sets calls updateData and create
161   * After calling this function the mem pointer will be increased by the size of the needed data
162   * @param mem pointer to where the appropriate data is located
163   * @param mode defines the mode, how the data should be loaded
164   * @return pointer to the newly created synchronisable
165   */
166  Synchronisable *Synchronisable::fabricate(uint8_t*& mem, uint8_t mode)
167  {
168    synchronisableHeader *header = (synchronisableHeader *)mem;
169
170    if(!header->dataAvailable)
171    {
172      mem += header->size;
173      return 0;
174    }
175
176    COUT(4) << "fabricating object with id: " << header->objectID << std::endl;
177
178    Identifier* id = ClassByID(header->classID);
179    assert(id);
180    BaseObject* creator = 0;
181    if (header->creatorID != OBJECTID_UNKNOWN)
182    {
183      Synchronisable* synchronisable_creator = Synchronisable::getSynchronisable(header->creatorID);
184      if (!synchronisable_creator)
185      {
186        mem += header->size; //.TODO: this suckz.... remove size from header
187        return 0;
188      }
189      else
190        creator = dynamic_cast<BaseObject*>(synchronisable_creator);
191    }
192    assert(getSynchronisable(header->objectID)==0);   //make sure no object with this id exists
193    BaseObject *bo = id->fabricate(creator);
194    assert(bo);
195    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
196    assert(no);
197    no->objectID=header->objectID;
198    no->creatorID=header->creatorID; //TODO: remove this
199    no->classID=header->classID;
200    COUT(4) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
201          // update data and create object/entity...
202    bool b = no->updateData(mem, mode, true);
203    assert(b);
204    if (b)
205    {
206        b = no->create();
207        assert(b);
208    }
209    return no;
210  }
211
212
213  /**
214   * Finds and deletes the Synchronisable with the appropriate objectID
215   * @param objectID objectID of the Synchronisable
216   * @return true/false
217   */
218  bool Synchronisable::deleteObject(unsigned int objectID){
219//     assert(getSynchronisable(objectID));
220    if(!getSynchronisable(objectID))
221      return false;
222    assert(getSynchronisable(objectID)->objectID==objectID);
223//     delete objectMap_[objectID];
224    Synchronisable *s = getSynchronisable(objectID);
225    if(s)
226      delete s;
227    else
228      return false;
229    return true;
230  }
231
232  /**
233   * This function looks up the objectID in the objectMap_ and returns a pointer to the right Synchronisable
234   * @param objectID objectID of the Synchronisable
235   * @return pointer to the Synchronisable with the objectID
236   */
237  Synchronisable* Synchronisable::getSynchronisable(unsigned int objectID){
238    std::map<unsigned int, Synchronisable*>::iterator it1;
239    it1 = objectMap_.find(objectID);
240    if (it1 != objectMap_.end())
241      return it1->second;
242
243    ObjectList<Synchronisable>::iterator it;
244    for(it = ObjectList<Synchronisable>::begin(); it; ++it){
245      if( it->getObjectID()==objectID ){
246        objectMap_[objectID] = *it;
247        return *it;
248      }
249    }
250    return NULL;
251  }
252
253
254  /**
255  * This function is used to register a variable to be synchronized
256  * also counts the total datasize needed to save the variables
257  * @param var pointer to the variable
258  * @param size size of the datatype the variable consists of
259  * @param t the type of the variable (DATA or STRING
260  * @param mode same as in getData
261  * @param cb callback object that should get called, if the value of the variable changes
262  */
263  void Synchronisable::registerVariable(void *var, int size, variableType t, uint8_t mode, NetworkCallbackBase *cb){
264    assert( mode==direction::toclient || mode==direction::toserver || mode==direction::serverMaster || mode==direction::clientMaster);
265    // create temporary synch.Var struct
266    synchronisableVariable *temp = new synchronisableVariable;
267    temp->size = size;
268    temp->var = var;
269    temp->mode = mode;
270    temp->type = t;
271    temp->callback = cb;
272    if( ( mode & direction::bidirectional ) )
273    {
274      if(t!=STRING)
275      {
276        temp->varBuffer = new uint8_t[size];
277        memcpy(temp->varBuffer, temp->var, size); //now fill the buffer for the first time
278      }
279      else
280      {
281        temp->varBuffer=new std::string( *static_cast<std::string*>(var) );
282      }
283      temp->varReference = 0;
284    }
285    COUT(5) << "Syncronisable::registering var with size: " << temp->size << " and type: " << temp->type << std::endl;
286    //std::cout << "push temp to syncList (at the bottom) " << datasize << std::endl;
287    COUT(5) << "Syncronisable::objectID: " << objectID << " this: " << this << " name: " << this->getIdentifier()->getName() << " networkID: " << this->getIdentifier()->getNetworkID() << std::endl;
288    syncList->push_back(temp);
289#ifndef NDEBUG
290    std::list<synchronisableVariable *>::iterator it = syncList->begin();
291    while(it!=syncList->end()){
292      assert(*it!=var);
293      it++;
294    }
295#endif
296  }
297
298  void Synchronisable::unregisterVariable(void *var){
299    std::list<synchronisableVariable *>::iterator it = syncList->begin();
300    while(it!=syncList->end()){
301      if( (*it)->var == var ){
302        delete *it;
303        syncList->erase(it);
304        return;
305      }
306      else
307        it++;
308    }
309    bool unregistered_nonexistent_variable = false;
310    assert(unregistered_nonexistent_variable); //if we reach this point something went wrong:
311    // the variable has not been registered before
312  }
313
314
315  /**
316   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID and classID to the given memory
317   * takes a pointer to already allocated memory (must have at least getSize bytes length)
318   * structure of the bitstream:
319   * |totalsize,objectID,classID,var1,var2,string1_length,string1,var3,...|
320   * length of varx: size saved int syncvarlist
321   * @param mem pointer to allocated memory with enough size
322   * @param id gamestateid of the gamestate to be saved (important for priorities)
323   * @param mode defines the direction in which the data will be send/received
324   *             0x1: server->client
325   *             0x2: client->server (not recommended)
326   *             0x3: bidirectional
327   * @return true: if !doSync or if everything was successfully saved
328   */
329  bool Synchronisable::getData(uint8_t*& mem, unsigned int id, uint8_t mode){
330    if(mode==0x0)
331      mode=state_;
332    //if this tick is we dont synchronise, then abort now
333    if(!doSync(id, mode))
334      return true;
335    //std::cout << "inside getData" << std::endl;
336    unsigned int tempsize = 0;
337    if(classID==0)
338      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
339
340    if (this->classID == (unsigned int)-1)
341        this->classID = this->getIdentifier()->getNetworkID();
342
343    assert(this->classID==this->getIdentifier()->getNetworkID());
344//     this->classID=this->getIdentifier()->getNetworkID(); // TODO: correct this
345    std::list<synchronisableVariable *>::iterator i;
346    unsigned int size;
347    size=getSize(id, mode);
348
349    // start copy header
350    synchronisableHeader *header = (synchronisableHeader *)mem;
351    header->size = size;
352    header->objectID = this->objectID;
353    header->creatorID = this->creatorID;
354    header->classID = this->classID;
355    header->dataAvailable = true;
356    tempsize += sizeof(synchronisableHeader);
357    mem += sizeof(synchronisableHeader);
358    // end copy header
359
360
361    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << " length: " << size << std::endl;
362    // copy to location
363    for(i=syncList->begin(); i!=syncList->end(); ++i){
364      if( ((*i)->mode & mode) == 0 ){
365        COUT(5) << "not getting data: " << std::endl;
366        continue;  // this variable should only be received
367      }
368
369      // =========== start bidirectional stuff =============
370      // if the variable gets synchronised bidirectional, then add the reference to the bytestream
371      if( ( (*i)->mode & direction::bidirectional ) == direction::bidirectional )
372      {
373        if( ( ((*i)->mode == direction::serverMaster) && (mode == 0x1) ) || \
374            ( ((*i)->mode == direction::clientMaster) && (mode == 0x2) ) )
375        {
376          // MASTER
377          if((*i)->type==DATA){
378            if( memcmp((*i)->var,(*i)->varBuffer,(*i)->size) != 0 ) //check whether the variable changed during the last tick
379            {
380              ((*i)->varReference)++;   //the variable changed so increase the refnr
381              memcpy((*i)->varBuffer, (*i)->var, (*i)->size); //set the buffer to the new value
382            }
383          }
384          else //STRING
385          {
386            if( *static_cast<std::string*>((*i)->var) != *static_cast<std::string*>((*i)->varBuffer) ) //the string changed
387            {
388              ((*i)->varReference)++;   //the variable changed
389              *static_cast<std::string*>((*i)->varBuffer) = *static_cast<std::string*>((*i)->var);  //now set the buffer to the new value
390            }
391          }
392        }
393        // copy the reference number to the stream
394        *(uint8_t*)mem = (*i)->varReference;
395        mem += sizeof( (*i)->varReference );
396        tempsize += sizeof( (*i)->varReference );
397      }
398      // ================== end bidirectional stuff
399
400      switch((*i)->type){
401        case DATA:
402          memcpy( (void *)(mem), (void*)((*i)->var), (*i)->size);
403          mem += (*i)->size;
404          tempsize += (*i)->size;
405          break;
406        case STRING:
407          memcpy( (void *)(mem), (void *)&((*i)->size), sizeof(size_t) );
408          mem += sizeof(size_t);
409          const char *data = ( ( *(std::string *) (*i)->var).c_str());
410          memcpy( mem, (void*)data, (*i)->size);
411          COUT(5) << "synchronisable: char: " << (const char *)(mem) << " data: " << data << " string: " << *(std::string *)((*i)->var) << std::endl;
412          mem += (*i)->size;
413          tempsize += (*i)->size + sizeof(size_t);
414          break;
415      }
416    }
417    assert(tempsize==size);
418    return true;
419  }
420
421
422  /**
423   * This function takes a bytestream and loads the data into the registered variables
424   * @param mem pointer to the bytestream
425   * @param mode same as in getData
426   * @return true/false
427   */
428  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback){
429    if(mode==0x0)
430      mode=state_;
431    std::list<synchronisableVariable *>::iterator i;
432    //assert(objectMode_!=0x0);
433    //assert( (mode ^ objectMode_) != 0);
434    if(syncList->empty()){
435      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
436      return false;
437    }
438
439    uint8_t *data=mem;
440    // start extract header
441    synchronisableHeader *syncHeader = (synchronisableHeader *)mem;
442    assert(syncHeader->objectID==this->objectID);
443    assert(syncHeader->creatorID==this->creatorID);
444    assert(this->classID==syncHeader->classID); //TODO: fix this!!! maybe a problem with the identifier ?
445    if(syncHeader->dataAvailable==false){
446      mem += syncHeader->size;
447      return true;
448    }
449
450    mem += sizeof(synchronisableHeader);
451    // stop extract header
452
453    COUT(5) << "Synchronisable: objectID " << syncHeader->objectID << ", classID " << syncHeader->classID << " size: " << syncHeader->size << " synchronising data" << std::endl;
454    for(i=syncList->begin(); i!=syncList->end() && mem <= data+syncHeader->size; i++){
455      if( ((*i)->mode ^ mode) == 0 ){
456        COUT(5) << "synchronisable: not updating variable " << std::endl;
457        // if we have a forcecallback then do the callback
458        continue;  // this variable should only be set
459      }
460      COUT(5) << "Synchronisable: element size: " << (*i)->size << " type: " << (*i)->type << std::endl;
461      bool callback=false;
462      bool master=false;
463
464      if( ( (*i)->mode & direction::bidirectional ) == direction::bidirectional )
465      {
466        uint8_t refNr = *(uint8_t *)mem;
467        if( ( ((*i)->mode == direction::serverMaster) && (mode == 0x1) ) || \
468            ( ((*i)->mode == direction::clientMaster) && (mode == 0x2) ) )
469        { // MASTER
470          master=true;
471          if( refNr != (*i)->varReference || ( memcmp((*i)->var, (*i)->varBuffer, (*i)->size) != 0 ) )
472          { // DISCARD data
473            if( (*i)->type == DATA )
474            {
475              mem += sizeof((*i)->varReference) + (*i)->size;
476            }
477            else //STRING
478            {
479              mem += sizeof(size_t) + *(size_t *)mem;
480            }
481            if( forceCallback && (*i)->callback)
482              (*i)->callback->call();
483            continue;
484          }//otherwise everything is ok and we update the value
485        }
486        else // SLAVE
487        {
488          if( (*i)->varReference == refNr ){
489            //discard data because it's outdated or not different to what we've got
490            if( (*i)->type == DATA )
491            {
492              mem += sizeof((*i)->varReference) + (*i)->size;
493            }
494            else //STRING
495            {
496              mem += sizeof(size_t) + *(size_t *)mem;
497            }
498            if( forceCallback && (*i)->callback)
499              (*i)->callback->call();
500            continue;
501          }
502          else
503            (*i)->varReference = refNr; //copy the reference value for this variable
504        }
505        mem += sizeof((*i)->varReference);
506      }
507
508      switch((*i)->type){
509        case DATA:
510          if((*i)->callback) // check whether this variable changed (but only if callback was set)
511          {
512            if(memcmp((*i)->var, mem, (*i)->size) != 0)
513              callback=true;
514          }
515          if( master )
516          {
517            if( callback || memcmp((*i)->var, mem, (*i)->size) != 0 )
518              //value changed, so set the buffer to the new value
519              memcpy((*i)->varBuffer, mem, (*i)->size);
520          }
521          memcpy((*i)->var, mem, (*i)->size);
522          mem += (*i)->size;
523          break;
524        case STRING:
525          (*i)->size = *(size_t *)mem;
526          mem += sizeof(size_t);
527
528          if( (*i)->callback) // check whether this string changed
529            if( *static_cast<std::string*>((*i)->var) != std::string((char *)mem) )
530              callback=true;
531          if( master )
532          {
533            if( callback || *static_cast<std::string*>((*i)->var) != std::string((char *)mem) )
534              //string changed. set the buffer to the new one
535              *static_cast<std::string*>((*i)->varBuffer)=*static_cast<std::string*>( (void*)(mem+sizeof(size_t)) );
536          }
537
538          *((std::string *)((*i)->var)) = std::string((const char*)mem);
539          COUT(5) << "synchronisable: char: " << (const char*)mem << " string: " << std::string((const char*)mem) << std::endl;
540          mem += (*i)->size;
541          break;
542      }
543      // call the callback function, if defined
544      if((callback || forceCallback) && (*i)->callback)
545        (*i)->callback->call();
546    }
547    assert(mem == data+syncHeader->size);
548    return true;
549  }
550
551  /**
552  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
553  * @param id id of the gamestate
554  * @param mode same as getData
555  * @return amount of bytes
556  */
557  uint32_t Synchronisable::getSize(unsigned int id, uint8_t mode){
558    int tsize=sizeof(synchronisableHeader);
559    if(mode==0x0)
560      mode=state_;
561    if(!doSync(id, mode))
562      return 0;
563    std::list<synchronisableVariable *>::iterator i;
564    for(i=syncList->begin(); i!=syncList->end(); i++){
565      if( ((*i)->mode & mode) == 0 )
566        continue;  // this variable should only be received, so dont add its size to the send-size
567      switch((*i)->type){
568      case DATA:
569        tsize+=(*i)->size;
570        break;
571      case STRING:
572        tsize+=sizeof(int);
573        (*i)->size=((std::string *)(*i)->var)->length()+1;
574        COUT(5) << "String size: " << (*i)->size << std::endl;
575        tsize+=(*i)->size;
576        break;
577      }
578      if( ( (*i)->mode & direction::bidirectional ) == direction::bidirectional )
579      {
580        tsize+=sizeof( (*i)->varReference );
581      }
582    }
583    return tsize;
584  }
585
586  /**
587   * This function determines, wheter the object should be saved to the bytestream (according to its syncmode/direction)
588   * @param id gamestate id
589   * @return true/false
590   */
591  bool Synchronisable::doSync(unsigned int id, uint8_t mode){
592    if(mode==0x0)
593      mode=state_;
594    return ( (objectMode_&mode)!=0 && (!syncList->empty() ) );
595  }
596
597  bool Synchronisable::doSelection(unsigned int id){
598    return true; //TODO: change this
599    //return ( id==0 || id%objectFrequency_==objectID%objectFrequency_ ) && ((objectMode_&state_)!=0);
600  }
601
602  /**
603   * This function looks at the header located in the bytestream and checks wheter objectID and classID match with the Synchronisables ones
604   * @param mem pointer to the bytestream
605   */
606  bool Synchronisable::isMyData(uint8_t* mem)
607  {
608    synchronisableHeader *header = (synchronisableHeader *)mem;
609    assert(header->objectID==this->objectID);
610    return header->dataAvailable;
611  }
612
613  /**
614   * This function sets the synchronisation mode of the object
615   * If set to 0x0 variables will not be synchronised at all
616   * If set to 0x1 variables will only be synchronised to the client
617   * If set to 0x2 variables will only be synchronised to the server
618   * If set to 0x3 variables will be synchronised bidirectionally (only if set so in registerVar)
619   * @param mode same as in registerVar
620   */
621  void Synchronisable::setObjectMode(uint8_t mode){
622    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
623    objectMode_=mode;
624  }
625
626
627}
Note: See TracBrowser for help on using the repository browser.