Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core5/src/libraries/network/synchronisable/Synchronisable.cc @ 5839

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

Fixed problem with scene and creators
creatorID is now always the objectID of the scene except for the case

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