Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6185 was 5929, checked in by rgrieder, 15 years ago

Merged core5 branch back to the trunk.
Key features include clean level unloading and an extended XML event system.

Two important notes:
Delete your keybindings.ini files! * or you will still get parser errors when loading the key bindings.
Delete build_dir/lib/modules/libgamestates.module! * or orxonox won't start.
Best thing to do is to delete the build folder ;)

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