Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network64/src/network/synchronisable/Synchronisable.cc @ 2245

Last change on this file since 2245 was 2245, checked in by scheusso, 15 years ago

most coding is done, still testing now
types should get transfered in platform independent formats now

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