Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/network/synchronisable/Synchronisable.cc @ 2736

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

finally got rid of these structs in our network datastream
this means we should now be able to play with gcc and msvc compiled versions together

  • Property svn:eol-style set to native
  • Property svn:mergeinfo set to (toggle deleted branches)
    /code/branches/network/src/network/synchronisable/Synchronisable.ccmergedeligible
    /code/branches/ceguilua/src/network/Synchronisable.cc1802-1808
    /code/branches/core3/src/network/Synchronisable.cc1572-1739
    /code/branches/gcc43/src/network/Synchronisable.cc1580
    /code/branches/gui/src/network/Synchronisable.cc1635-1723
    /code/branches/input/src/network/Synchronisable.cc1629-1636
    /code/branches/objecthierarchy/src/network/Synchronisable.cc1911-2085,​2100,​2110-2169
    /code/branches/physics_merge/src/network/synchronisable/Synchronisable.cc2436-2457
    /code/branches/pickups/src/network/Synchronisable.cc1926-2086
    /code/branches/questsystem/src/network/Synchronisable.cc1894-2088
    /code/branches/script_trigger/src/network/Synchronisable.cc1295-1953,​1955
    /code/branches/weapon/src/network/Synchronisable.cc1925-2094
File size: 15.1 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  {
[2655]147    SynchronisableHeader header(mem);
[1856]148
[2655]149    if(!header.isDataAvailable())
[2087]150    {
[2655]151      mem += header.getDataSize();
[2087]152      return 0;
153    }
[2171]154
[2655]155    COUT(4) << "fabricating object with id: " << header.getObjectID() << std::endl;
[1856]156
[2655]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;
[2655]166    if (header.getCreatorID() != OBJECTID_UNKNOWN)
[2087]167    {
[2655]168      Synchronisable* synchronisable_creator = Synchronisable::getSynchronisable(header.getCreatorID());
[2087]169      if (!synchronisable_creator)
170      {
[2655]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    }
[2655]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);
[2655]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  /**
241  * This function is used to register a variable to be synchronized
242  * also counts the total datasize needed to save the variables
243  * @param var pointer to the variable
244  * @param size size of the datatype the variable consists of
[2171]245  * @param t the type of the variable (DATA or STRING
[1907]246  * @param mode same as in getData
247  * @param cb callback object that should get called, if the value of the variable changes
[1505]248  */
[2245]249
250/*  void Synchronisable::registerVariable(void *var, int size, variableType t, uint8_t mode, NetworkCallbackBase *cb){
[2485]251    assert( mode==variableDirection::toclient || mode==variableDirection::toserver || mode==variableDirection::serverMaster || mode==variableDirection::clientMaster);
[1505]252    // create temporary synch.Var struct
253    synchronisableVariable *temp = new synchronisableVariable;
254    temp->size = size;
255    temp->var = var;
[1639]256    temp->mode = mode;
[1505]257    temp->type = t;
[1534]258    temp->callback = cb;
[2485]259    if( ( mode & variableDirection::bidirectional ) )
[2087]260    {
[2171]261      if(t!=STRING)
262      {
263        temp->varBuffer = new uint8_t[size];
264        memcpy(temp->varBuffer, temp->var, size); //now fill the buffer for the first time
265      }
266      else
267      {
268        temp->varBuffer=new std::string( *static_cast<std::string*>(var) );
269      }
[2087]270      temp->varReference = 0;
271    }
[1639]272    COUT(5) << "Syncronisable::registering var with size: " << temp->size << " and type: " << temp->type << std::endl;
[1505]273    //std::cout << "push temp to syncList (at the bottom) " << datasize << std::endl;
274    COUT(5) << "Syncronisable::objectID: " << objectID << " this: " << this << " name: " << this->getIdentifier()->getName() << " networkID: " << this->getIdentifier()->getNetworkID() << std::endl;
275    syncList->push_back(temp);
[1907]276#ifndef NDEBUG
277    std::list<synchronisableVariable *>::iterator it = syncList->begin();
278    while(it!=syncList->end()){
279      assert(*it!=var);
280      it++;
281    }
282#endif
[2245]283  }*/
[1856]284
[2485]285
[1735]286  /**
[1907]287   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID and classID to the given memory
[1735]288   * takes a pointer to already allocated memory (must have at least getSize bytes length)
[1751]289   * structure of the bitstream:
[1907]290   * |totalsize,objectID,classID,var1,var2,string1_length,string1,var3,...|
291   * length of varx: size saved int syncvarlist
292   * @param mem pointer to allocated memory with enough size
293   * @param id gamestateid of the gamestate to be saved (important for priorities)
294   * @param mode defines the direction in which the data will be send/received
295   *             0x1: server->client
296   *             0x2: client->server (not recommended)
297   *             0x3: bidirectional
[2087]298   * @return true: if !doSync or if everything was successfully saved
[1735]299   */
[2309]300  bool Synchronisable::getData(uint8_t*& mem, int32_t id, uint8_t mode){
[2171]301    if(mode==0x0)
302      mode=state_;
[1907]303    //if this tick is we dont synchronise, then abort now
[2171]304    if(!doSync(id, mode))
[1907]305      return true;
[1735]306    //std::cout << "inside getData" << std::endl;
[2309]307    uint32_t tempsize = 0;
[2316]308    if (this->classID==0)
[1735]309      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
[2087]310
[2309]311    if (this->classID == static_cast<uint32_t>(-1))
[2087]312        this->classID = this->getIdentifier()->getNetworkID();
313
[1907]314    assert(this->classID==this->getIdentifier()->getNetworkID());
315//     this->classID=this->getIdentifier()->getNetworkID(); // TODO: correct this
[2245]316    std::list<SynchronisableVariableBase*>::iterator i;
[2309]317    uint32_t size;
[1907]318    size=getSize(id, mode);
[1856]319
[1735]320    // start copy header
[2655]321    SynchronisableHeader header(mem);
322    header.setDataSize( size );
323    header.setObjectID( this->objectID );
324    header.setCreatorID( this->creatorID );
325    header.setClassID( this->classID );
326    header.setDataAvailable( true );
327    tempsize += SynchronisableHeader::getSize();
328    mem += SynchronisableHeader::getSize();
[1735]329    // end copy header
[1856]330
331
[1735]332    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << " length: " << size << std::endl;
333    // copy to location
[2245]334    for(i=syncList.begin(); i!=syncList.end(); ++i){
335      (*i)->getData( mem, mode );
336      tempsize += (*i)->getSize( mode );
[1735]337    }
338    assert(tempsize==size);
339    return true;
340  }
[1505]341
[1856]342
[1505]343  /**
[1907]344   * This function takes a bytestream and loads the data into the registered variables
345   * @param mem pointer to the bytestream
346   * @param mode same as in getData
[1735]347   * @return true/false
348   */
[2171]349  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback){
[1735]350    if(mode==0x0)
351      mode=state_;
[2245]352    std::list<SynchronisableVariableBase *>::iterator i;
[2171]353    //assert(objectMode_!=0x0);
354    //assert( (mode ^ objectMode_) != 0);
[2245]355    if(syncList.empty()){
[2419]356      assert(0);
[1735]357      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
358      return false;
359    }
[1856]360
[2245]361    uint8_t* data=mem;
[1735]362    // start extract header
[2655]363    SynchronisableHeader syncHeader(mem);
364    assert(syncHeader.getObjectID()==this->objectID);
365    assert(syncHeader.getCreatorID()==this->creatorID);
366    assert(syncHeader.getClassID()==this->classID);
367    if(syncHeader.isDataAvailable()==false){
368      mem += syncHeader.getDataSize();
[1751]369      return true;
[1907]370    }
[1856]371
[2655]372    mem += SynchronisableHeader::getSize();
[1907]373    // stop extract header
[2087]374
[2655]375    //COUT(5) << "Synchronisable: objectID " << syncHeader.getObjectID() << ", classID " << syncHeader.getClassID() << " size: " << syncHeader.getDataSize() << " synchronising data" << std::endl;
376    for(i=syncList.begin(); i!=syncList.end(); i++)
[2245]377    {
[2655]378      assert( mem <= data+syncHeader.getDataSize() ); // always make sure we don't exceed the datasize in our stream
[2245]379      (*i)->putData( mem, mode, forceCallback );
[1735]380    }
[2655]381    assert(mem == data+syncHeader.getDataSize());
[1735]382    return true;
383  }
[1505]384
385  /**
386  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
[1907]387  * @param id id of the gamestate
388  * @param mode same as getData
[1505]389  * @return amount of bytes
390  */
[2309]391  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode){
[2655]392    int tsize=SynchronisableHeader::getSize();
[1505]393    if(mode==0x0)
394      mode=state_;
[2171]395    if(!doSync(id, mode))
396      return 0;
[2245]397    std::list<SynchronisableVariableBase*>::iterator i;
398    for(i=syncList.begin(); i!=syncList.end(); i++){
399      tsize += (*i)->getSize( mode );
[1505]400    }
401    return tsize;
402  }
[1639]403
[1735]404  /**
[1907]405   * This function determines, wheter the object should be saved to the bytestream (according to its syncmode/direction)
406   * @param id gamestate id
407   * @return true/false
[1735]408   */
[2309]409  bool Synchronisable::doSync(int32_t id, uint8_t mode){
[2171]410    if(mode==0x0)
411      mode=state_;
[2245]412    return ( (objectMode_&mode)!=0 && (!syncList.empty() ) );
[1735]413  }
[1856]414
[1907]415  /**
416   * This function looks at the header located in the bytestream and checks wheter objectID and classID match with the Synchronisables ones
417   * @param mem pointer to the bytestream
418   */
419  bool Synchronisable::isMyData(uint8_t* mem)
[1735]420  {
[2655]421    SynchronisableHeader header(mem);
422    assert(header.getObjectID()==this->objectID);
423    return header.isDataAvailable();
[1735]424  }
[1856]425
[1907]426  /**
427   * This function sets the synchronisation mode of the object
[2171]428   * If set to 0x0 variables will not be synchronised at all
[1907]429   * If set to 0x1 variables will only be synchronised to the client
430   * If set to 0x2 variables will only be synchronised to the server
431   * If set to 0x3 variables will be synchronised bidirectionally (only if set so in registerVar)
432   * @param mode same as in registerVar
433   */
[2171]434  void Synchronisable::setObjectMode(uint8_t mode){
[2087]435    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
[1751]436    objectMode_=mode;
[1505]437  }
438
[2485]439
[1505]440}
Note: See TracBrowser for help on using the repository browser.