Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/network/synchronisable/Synchronisable.cc @ 2743

Last change on this file since 2743 was 2710, checked in by rgrieder, 16 years ago

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

File size: 13.2 KB
RevLine 
[1505]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#include "Synchronisable.h"
32
[1837]33#include <cstring>
[2087]34#include <string>
[1505]35#include <iostream>
[1735]36#include <assert.h>
[1505]37
38#include "core/CoreIncludes.h"
[1735]39#include "core/BaseObject.h"
[1534]40// #include "core/Identifier.h"
[1505]41
[2211]42#include "network/Host.h"
[2171]43namespace orxonox
[1505]44{
[1639]45
[2309]46  std::map<uint32_t, Synchronisable *> Synchronisable::objectMap_;
47  std::queue<uint32_t> Synchronisable::deletedObjects_;
[1639]48
[2171]49  uint8_t Synchronisable::state_=0x1; // detemines wheter we are server (default) or client
[1639]50
[1505]51  /**
52  * Constructor:
[1907]53  * Initializes all Variables and sets the right objectID
[1505]54  */
[2171]55  Synchronisable::Synchronisable(BaseObject* creator){
[1505]56    RegisterRootObject(Synchronisable);
[1907]57    static uint32_t idCounter=0;
58    objectMode_=0x1; // by default do not send data to server
[2171]59    if ( !Host::running() || ( Host::running() && Host::isServer() ) )
60    {
61      this->objectID = idCounter++; //this is only needed when running a server
62    //add synchronisable to the objectMap
63      objectMap_[this->objectID] = this;
64    }
65    else
66      objectID=OBJECTID_UNKNOWN;
[2309]67    classID = static_cast<uint32_t>(-1);
[2087]68
[2415]69    // set standard priority
70    this->setPriority( priority::normal );
[2171]71
[2415]72    // get creator id
[2087]73    this->creatorID = OBJECTID_UNKNOWN;
74
75    searchcreatorID:
76    if (creator)
77    {
78        Synchronisable* synchronisable_creator = dynamic_cast<Synchronisable*>(creator);
79        if (synchronisable_creator && synchronisable_creator->objectMode_)
80        {
81            this->creatorID = synchronisable_creator->getObjectID();
82        }
83        else if (creator != creator->getCreator())
84        {
85            creator = creator->getCreator();
86            goto searchcreatorID;
87        }
88    }
[1505]89  }
90
[1907]91  /**
[2087]92   * Destructor:
[1907]93   * Delete all callback objects and remove objectID from the objectMap_
94   */
[1505]95  Synchronisable::~Synchronisable(){
[1534]96    // delete callback function objects
[2171]97    if(!Identifier::isCreatingHierarchy()){
[2245]98      for(std::list<SynchronisableVariableBase*>::iterator it = syncList.begin(); it!=syncList.end(); it++)
99        delete (*it);
[2171]100      if (this->objectMode_ != 0x0 && (Host::running() && Host::isServer()))
[2087]101        deletedObjects_.push(objectID);
[1907]102//       COUT(3) << "destruct synchronisable +++" << objectID << " | " << classID << std::endl;
103//       COUT(3) << " bump ---" << objectID << " | " << &objectMap_ << std::endl;
104//       assert(objectMap_[objectID]->objectID==objectID);
105//       objectMap_.erase(objectID);
106    }
[2309]107    std::map<uint32_t, Synchronisable*>::iterator it;
[2171]108    it = objectMap_.find(objectID);
109    if (it != objectMap_.end())
110      objectMap_.erase(it);
[2485]111
[2482]112    //HACK HACK HACK HACK HACK HACK
[2540]113    // this hack ensures that children of this object also get destroyed
[2482]114//     ObjectList<Synchronisable>::iterator it2, it3;
115//     // get total size of gamestate
116//     for(it2 = ObjectList<Synchronisable>::begin(); it2; ++it2)
117//     {
118//       if ( it2->getCreatorID() == this->objectID && it2->getCreatorID() != OBJECTID_UNKNOWN )
119//       {
120//         Synchronisable::deleteObject( it2->getObjectID() );
121//       }
122//     }
123    //HACK HACK HACK HACK HACK HACK
[1505]124  }
[1639]125
[2087]126
[1907]127  /**
128   * This function sets the internal mode for synchronisation
129   * @param b true if this object is located on a client or on a server
130   */
[1505]131  void Synchronisable::setClient(bool b){
132    if(b) // client
133      state_=0x2;
134    else  // server
135      state_=0x1;
136  }
[1856]137
[1907]138  /**
139   * This function fabricated a new synchrnisable (and children of it), sets calls updateData and create
140   * After calling this function the mem pointer will be increased by the size of the needed data
141   * @param mem pointer to where the appropriate data is located
142   * @param mode defines the mode, how the data should be loaded
143   * @return pointer to the newly created synchronisable
144   */
[2171]145  Synchronisable *Synchronisable::fabricate(uint8_t*& mem, uint8_t mode)
[1735]146  {
[2662]147    SynchronisableHeader header(mem);
[1856]148
[2662]149    if(!header.isDataAvailable())
[2087]150    {
[2662]151      mem += header.getDataSize();
[2087]152      return 0;
153    }
[2171]154
[2662]155    COUT(4) << "fabricating object with id: " << header.getObjectID() << std::endl;
[1856]156
[2662]157    Identifier* id = ClassByID(header.getClassID());
[2485]158    if (!id)
159    {
160        COUT(0) << "Assertion failed: id" << std::endl;
161        COUT(0) << "Possible reason for this error: Client received a synchronizable object whose class has no factory." << std::endl;
162        abort();
163    }
[1907]164    assert(id);
[2171]165    BaseObject* creator = 0;
[2662]166    if (header.getCreatorID() != OBJECTID_UNKNOWN)
[2087]167    {
[2662]168      Synchronisable* synchronisable_creator = Synchronisable::getSynchronisable(header.getCreatorID());
[2087]169      if (!synchronisable_creator)
170      {
[2662]171        mem += header.getDataSize(); //.TODO: this suckz.... remove size from header
172        assert(0); // TODO: uncomment this if we have a clean objecthierarchy (with destruction of children of objects) ^^
[2087]173        return 0;
174      }
175      else
[2171]176        creator = dynamic_cast<BaseObject*>(synchronisable_creator);
[2087]177    }
[2662]178    assert(getSynchronisable(header.getObjectID())==0);   //make sure no object with this id exists
[2171]179    BaseObject *bo = id->fabricate(creator);
[2087]180    assert(bo);
[1735]181    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
182    assert(no);
[2662]183    no->objectID=header.getObjectID();
184    no->creatorID=header.getCreatorID(); //TODO: remove this
185    no->classID=header.getClassID();
[2087]186    COUT(4) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
[1735]187          // update data and create object/entity...
[2087]188    bool b = no->updateData(mem, mode, true);
[1907]189    assert(b);
[2087]190    if (b)
191    {
[2245]192//        b = no->create();
[2087]193        assert(b);
194    }
[1907]195    return no;
196  }
197
[2087]198
[1907]199  /**
200   * Finds and deletes the Synchronisable with the appropriate objectID
201   * @param objectID objectID of the Synchronisable
202   * @return true/false
203   */
[2309]204  bool Synchronisable::deleteObject(uint32_t objectID){
[1907]205//     assert(getSynchronisable(objectID));
206    if(!getSynchronisable(objectID))
[1735]207      return false;
[1907]208    assert(getSynchronisable(objectID)->objectID==objectID);
209//     delete objectMap_[objectID];
210    Synchronisable *s = getSynchronisable(objectID);
211    if(s)
212      delete s;
213    else
[1735]214      return false;
215    return true;
216  }
[2087]217
[1907]218  /**
219   * This function looks up the objectID in the objectMap_ and returns a pointer to the right Synchronisable
220   * @param objectID objectID of the Synchronisable
221   * @return pointer to the Synchronisable with the objectID
222   */
[2309]223  Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID){
224    std::map<uint32_t, Synchronisable*>::iterator it1;
[2171]225    it1 = objectMap_.find(objectID);
226    if (it1 != objectMap_.end())
227      return it1->second;
228
229    ObjectList<Synchronisable>::iterator it;
230    for(it = ObjectList<Synchronisable>::begin(); it; ++it){
231      if( it->getObjectID()==objectID ){
232        objectMap_[objectID] = *it;
233        return *it;
234      }
[1907]235    }
236    return NULL;
237  }
238
[2087]239
[1505]240  /**
[1907]241   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID and classID to the given memory
[1735]242   * takes a pointer to already allocated memory (must have at least getSize bytes length)
[1751]243   * structure of the bitstream:
[1907]244   * |totalsize,objectID,classID,var1,var2,string1_length,string1,var3,...|
245   * length of varx: size saved int syncvarlist
246   * @param mem pointer to allocated memory with enough size
247   * @param id gamestateid of the gamestate to be saved (important for priorities)
248   * @param mode defines the direction in which the data will be send/received
249   *             0x1: server->client
250   *             0x2: client->server (not recommended)
251   *             0x3: bidirectional
[2087]252   * @return true: if !doSync or if everything was successfully saved
[1735]253   */
[2309]254  bool Synchronisable::getData(uint8_t*& mem, int32_t id, uint8_t mode){
[2171]255    if(mode==0x0)
256      mode=state_;
[1907]257    //if this tick is we dont synchronise, then abort now
[2171]258    if(!doSync(id, mode))
[1907]259      return true;
[1735]260    //std::cout << "inside getData" << std::endl;
[2309]261    uint32_t tempsize = 0;
[2316]262    if (this->classID==0)
[1735]263      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
[2087]264
[2309]265    if (this->classID == static_cast<uint32_t>(-1))
[2087]266        this->classID = this->getIdentifier()->getNetworkID();
267
[1907]268    assert(this->classID==this->getIdentifier()->getNetworkID());
269//     this->classID=this->getIdentifier()->getNetworkID(); // TODO: correct this
[2245]270    std::list<SynchronisableVariableBase*>::iterator i;
[2309]271    uint32_t size;
[1907]272    size=getSize(id, mode);
[1856]273
[1735]274    // start copy header
[2662]275    SynchronisableHeader header(mem);
276    header.setDataSize( size );
277    header.setObjectID( this->objectID );
278    header.setCreatorID( this->creatorID );
279    header.setClassID( this->classID );
280    header.setDataAvailable( true );
281    tempsize += SynchronisableHeader::getSize();
282    mem += SynchronisableHeader::getSize();
[1735]283    // end copy header
[1856]284
285
[1735]286    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << " length: " << size << std::endl;
287    // copy to location
[2245]288    for(i=syncList.begin(); i!=syncList.end(); ++i){
289      (*i)->getData( mem, mode );
290      tempsize += (*i)->getSize( mode );
[1735]291    }
292    assert(tempsize==size);
293    return true;
294  }
[1505]295
[1856]296
[1505]297  /**
[1907]298   * This function takes a bytestream and loads the data into the registered variables
299   * @param mem pointer to the bytestream
300   * @param mode same as in getData
[1735]301   * @return true/false
302   */
[2171]303  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback){
[1735]304    if(mode==0x0)
305      mode=state_;
[2245]306    std::list<SynchronisableVariableBase *>::iterator i;
[2171]307    //assert(objectMode_!=0x0);
308    //assert( (mode ^ objectMode_) != 0);
[2245]309    if(syncList.empty()){
[2419]310      assert(0);
[1735]311      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
312      return false;
313    }
[1856]314
[2245]315    uint8_t* data=mem;
[1735]316    // start extract header
[2662]317    SynchronisableHeader syncHeader(mem);
318    assert(syncHeader.getObjectID()==this->objectID);
319    assert(syncHeader.getCreatorID()==this->creatorID);
320    assert(syncHeader.getClassID()==this->classID);
321    if(syncHeader.isDataAvailable()==false){
322      mem += syncHeader.getDataSize();
[1751]323      return true;
[1907]324    }
[1856]325
[2662]326    mem += SynchronisableHeader::getSize();
[1907]327    // stop extract header
[2087]328
[2662]329    //COUT(5) << "Synchronisable: objectID " << syncHeader.getObjectID() << ", classID " << syncHeader.getClassID() << " size: " << syncHeader.getDataSize() << " synchronising data" << std::endl;
330    for(i=syncList.begin(); i!=syncList.end(); i++)
[2245]331    {
[2662]332      assert( mem <= data+syncHeader.getDataSize() ); // always make sure we don't exceed the datasize in our stream
[2245]333      (*i)->putData( mem, mode, forceCallback );
[1735]334    }
[2662]335    assert(mem == data+syncHeader.getDataSize());
[1735]336    return true;
337  }
[1505]338
339  /**
340  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
[1907]341  * @param id id of the gamestate
342  * @param mode same as getData
[1505]343  * @return amount of bytes
344  */
[2309]345  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode){
[2662]346    int tsize=SynchronisableHeader::getSize();
[1505]347    if(mode==0x0)
348      mode=state_;
[2171]349    if(!doSync(id, mode))
350      return 0;
[2245]351    std::list<SynchronisableVariableBase*>::iterator i;
352    for(i=syncList.begin(); i!=syncList.end(); i++){
353      tsize += (*i)->getSize( mode );
[1505]354    }
355    return tsize;
356  }
[1639]357
[1735]358  /**
[1907]359   * This function determines, wheter the object should be saved to the bytestream (according to its syncmode/direction)
360   * @param id gamestate id
361   * @return true/false
[1735]362   */
[2309]363  bool Synchronisable::doSync(int32_t id, uint8_t mode){
[2171]364    if(mode==0x0)
365      mode=state_;
[2245]366    return ( (objectMode_&mode)!=0 && (!syncList.empty() ) );
[1735]367  }
[1856]368
[1907]369  /**
370   * This function looks at the header located in the bytestream and checks wheter objectID and classID match with the Synchronisables ones
371   * @param mem pointer to the bytestream
372   */
373  bool Synchronisable::isMyData(uint8_t* mem)
[1735]374  {
[2662]375    SynchronisableHeader header(mem);
376    assert(header.getObjectID()==this->objectID);
377    return header.isDataAvailable();
[1735]378  }
[1856]379
[1907]380  /**
381   * This function sets the synchronisation mode of the object
[2171]382   * If set to 0x0 variables will not be synchronised at all
[1907]383   * If set to 0x1 variables will only be synchronised to the client
384   * If set to 0x2 variables will only be synchronised to the server
385   * If set to 0x3 variables will be synchronised bidirectionally (only if set so in registerVar)
386   * @param mode same as in registerVar
387   */
[2171]388  void Synchronisable::setObjectMode(uint8_t mode){
[2087]389    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
[1751]390    objectMode_=mode;
[1505]391  }
392
[2485]393
[1505]394}
Note: See TracBrowser for help on using the repository browser.