Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/network/synchronisable/Synchronisable.cc @ 9001

Last change on this file since 9001 was 8807, checked in by landauf, 13 years ago

Replaced COUT with orxout in network library. Tried to set levels and contexts in a more or less useful way, but not really optimized. Used contexts network, packets, and master_server.
Please use endl instead of \n in the future (@smerkli) ;)

  • Property svn:eol-style set to native
File size: 16.1 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  {
53    RegisterRootObject(Synchronisable);
54    static uint32_t idCounter=0;
55    objectMode_=0x1; // by default do not send data to server
56    if ( GameMode::isMaster()/* || ( Host::running() && Host::isServer() )*/ )
57    {
58      this->setObjectID( idCounter++ );
59    }
60    else
61    {
62      objectID_=OBJECTID_UNKNOWN;
63    }
64    classID_ = static_cast<uint32_t>(-1);
65
66    // set dataSize to 0
67    this->dataSize_ = 0;
68    // set standard priority
69    this->setPriority( Priority::Normal );
70
71    // get creator id
72    if( creator )
73      this->creatorID_ = creator->getSceneID();
74    else
75      this->creatorID_ = OBJECTID_UNKNOWN;
76  }
77
78  /**
79   * Destructor:
80   * Delete all callback objects and remove objectID_ from the objectMap_
81   */
82  Synchronisable::~Synchronisable()
83  {
84    // delete callback function objects
85    if(!Identifier::isCreatingHierarchy()){
86      // remove object from the static objectMap
87      if (this->objectMode_ != 0x0 && (Host::running() && Host::isServer()))
88        deletedObjects_.push(objectID_);
89    }
90    // delete all Synchronisable Variables from syncList_ ( which are also in stringList_ )
91    for(std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin(); it!=syncList_.end(); it++)
92      delete (*it);
93    syncList_.clear();
94    stringList_.clear();
95    std::map<uint32_t, Synchronisable*>::iterator it2;
96    it2 = objectMap_.find(objectID_);
97    if (it2 != objectMap_.end())
98      objectMap_.erase(it2);
99
100  }
101
102
103  /**
104   * This function sets the internal mode for synchronisation
105   * @param b true if this object is located on a client or on a server
106   */
107  void Synchronisable::setClient(bool b)
108  {
109    if(b) // client
110      state_=0x2;
111    else  // server
112      state_=0x1;
113  }
114
115  /**
116   * This function fabricated a new synchrnisable (and children of it), sets calls updateData and create
117   * After calling this function the mem pointer will be increased by the size of the needed data
118   * @param mem pointer to where the appropriate data is located
119   * @param mode defines the mode, how the data should be loaded
120   * @return pointer to the newly created synchronisable
121   */
122  Synchronisable *Synchronisable::fabricate(uint8_t*& mem, uint8_t mode)
123  {
124    SynchronisableHeader header(mem);
125    if( header.isDiffed() )
126    {
127      mem += header.getDataSize() + header.getSize();
128      return 0;
129    }
130//     assert( !header.isDiffed() );
131
132    orxout(verbose, context::network) << "fabricating object with id: " << header.getObjectID() << endl;
133
134    Identifier* id = ClassByID(header.getClassID());
135    if (!id)
136    {
137        for(int i = 0; i<160; i++)
138            orxout(user_error, context::network) << "classid: " << i << " identifier: " << ClassByID(i) << endl;
139        orxout(user_error, context::network) << "Assertion failed: id" << endl;
140        orxout(user_error, context::network) << "Possible reason for this error: Client received a synchronizable object whose class has no factory." << endl;
141        abort();
142    }
143    assert(id);
144    BaseObject* creator = 0;
145    if (header.getCreatorID() != OBJECTID_UNKNOWN)
146    {
147      Synchronisable* synchronisable_creator = Synchronisable::getSynchronisable(header.getCreatorID());
148      if (!synchronisable_creator)
149      {
150        mem += header.getDataSize()+SynchronisableHeader::getSize(); //.TODO: this suckz.... remove size from header
151        assert(0); // TODO: uncomment this if we have a clean objecthierarchy (with destruction of children of objects) ^^
152        return 0;
153      }
154      else
155        creator = orxonox_cast<BaseObject*>(synchronisable_creator);
156    }
157    assert(getSynchronisable(header.getObjectID())==0);   //make sure no object with this id exists
158    BaseObject *bo = id->fabricate(creator);
159    assert(bo);
160    Synchronisable *no = orxonox_cast<Synchronisable*>(bo);
161    assert(no);
162    assert( Synchronisable::objectMap_.find(header.getObjectID()) == Synchronisable::objectMap_.end() );
163    no->setObjectID(header.getObjectID());
164    //no->creatorID=header.getCreatorID(); //TODO: remove this
165    no->setClassID(header.getClassID());
166    assert(no->creatorID_ == header.getCreatorID());
167    if( creator )
168      bo->setLevel(creator->getLevel());          // Note: this ensures that the level is known on the client for child objects of the scene (and the scene itself)
169    //assert(no->classID_ == header.getClassID());
170    orxout(verbose, context::network) << "fabricate objectID_: " << no->objectID_ << " classID_: " << no->classID_ << endl;
171          // update data and create object/entity...
172    bool b = no->updateData(mem, mode, true);
173    assert(b);
174    if (b)
175    {
176//        b = no->create();
177        assert(b);
178    }
179    return no;
180  }
181
182
183  /**
184   * Finds and deletes the Synchronisable with the appropriate objectID_
185   * @param objectID_ objectID_ of the Synchronisable
186   * @return true/false
187   */
188  bool Synchronisable::deleteObject(uint32_t objectID_)
189  {
190    if(!getSynchronisable(objectID_))
191      return false;
192    assert(getSynchronisable(objectID_)->objectID_==objectID_);
193    Synchronisable *s = getSynchronisable(objectID_);
194    if(s)
195      s->destroy(); // or delete?
196    else
197      return false;
198    return true;
199  }
200
201  /**
202   * This function looks up the objectID_ in the objectMap_ and returns a pointer to the right Synchronisable
203   * @param objectID_ objectID_ of the Synchronisable
204   * @return pointer to the Synchronisable with the objectID_
205   */
206  Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID_)
207  {
208    std::map<uint32_t, Synchronisable*>::iterator it1;
209    it1 = objectMap_.find(objectID_);
210    if (it1 != objectMap_.end())
211      return it1->second;
212    // if the objects not in the map it should'nt exist at all anymore
213    return NULL;
214  }
215
216
217  /**
218   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID_ and classID_ to the given memory
219   * takes a pointer to already allocated memory (must have at least getSize bytes length)
220   * structure of the bitstream:
221   * |totalsize,objectID_,classID_,var1,var2,string1_length,string1,var3,...|
222   * length of varx: size saved int syncvarlist
223   * @param mem pointer to allocated memory with enough size
224   * @param sizes vector containing sizes of all objects in gamestate (to be appended)
225   * @param id gamestateid of the gamestate to be saved (important for priorities)
226   * @param mode defines the direction in which the data will be send/received
227   *             0x1: server->client
228   *             0x2: client->server
229   *             0x3: bidirectional
230   * @return true: if !doSync or if everything was successfully saved
231   */
232  uint32_t Synchronisable::getData(uint8_t*& mem, std::vector<uint32_t>& sizes, int32_t id, uint8_t mode)
233  {
234    unsigned int test = 0;
235    if(mode==0x0)
236      mode=state_;
237    //if this tick is we dont synchronise, then abort now
238    if(!doSync(/*id,*/ mode))
239      return 0;
240    uint32_t tempsize = 0;
241#ifndef NDEBUG
242    uint8_t* oldmem = mem;
243    if (this->classID_==0)
244      orxout(internal_info, context::network) << "classid 0 " << this->getIdentifier()->getName() << endl;
245#endif
246
247    if (this->classID_ == static_cast<uint32_t>(-1))
248        this->classID_ = this->getIdentifier()->getNetworkID();
249
250    assert(ClassByID(this->classID_));
251    assert(this->classID_==this->getIdentifier()->getNetworkID());
252    assert(this->objectID_!=OBJECTID_UNKNOWN);
253    std::vector<SynchronisableVariableBase*>::iterator i;
254
255    // start copy header
256    SynchronisableHeader header(mem);
257    mem += SynchronisableHeader::getSize();
258    // end copy header
259
260    orxout(verbose_more, context::network) << "getting data from objectID_: " << objectID_ << ", classID_: " << classID_ << endl;
261//     orxout(verbose, context::network) << "objectid: " << this->objectID_ << ":";
262    // copy to location
263    for(i=syncList_.begin(); i!=syncList_.end(); ++i)
264    {
265      uint32_t varsize = (*i)->getData( mem, mode );
266//       orxout(verbose, context::network) << " " << varsize;
267      tempsize += varsize;
268      sizes.push_back(varsize);
269      ++test;
270      //tempsize += (*i)->getSize( mode );
271    }
272    assert(tempsize!=0);  // if this happens an empty object (with no variables) would be transmitted
273//     orxout(verbose, context::network) << endl;
274
275    header.setObjectID( this->objectID_ );
276    header.setCreatorID( this->creatorID_ );
277    header.setClassID( this->classID_ );
278    header.setDataSize( tempsize );
279    assert( tempsize == mem-oldmem-SynchronisableHeader::getSize() );
280    assert( test == this->getNrOfVariables() );
281    header.setDiffed(false);
282    tempsize += SynchronisableHeader::getSize();
283
284#ifndef NDEBUG
285    uint32_t size;
286    size=getSize(id, mode);
287    assert(tempsize==size);
288#endif
289    return tempsize;
290  }
291
292
293  /**
294   * This function takes a bytestream and loads the data into the registered variables
295   * @param mem pointer to the bytestream
296   * @param mode same as in getData
297   * @param forceCallback this makes updateData call each callback
298   * @return true/false
299   */
300  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback)
301  {
302    if(mode==0x0)
303      mode=state_;
304   
305    if(syncList_.empty())
306    {
307      orxout(internal_warning, context::network) << "Synchronisable::updateData syncList_ is empty" << endl;
308      assert(0);
309      return false;
310    }
311
312    uint8_t* data=mem;
313    // start extract header
314    SynchronisableHeaderLight syncHeaderLight(mem);
315    assert(syncHeaderLight.getObjectID()==this->getObjectID());
316   
317    if( !this->doReceive(mode) )
318    {
319      uint32_t headerSize;
320      if( syncHeaderLight.isDiffed() )
321        headerSize = SynchronisableHeaderLight::getSize();
322      else
323        headerSize = SynchronisableHeader::getSize();
324      mem += syncHeaderLight.getDataSize() + headerSize;
325      return true;
326    }
327
328    //orxout(verbose_more, context::network) << "Synchronisable: objectID_ " << syncHeader.getObjectID() << ", classID_ " << syncHeader.getClassID() << " size: " << syncHeader.getDataSize() << " synchronising data" << endl;
329    if( !syncHeaderLight.isDiffed() )
330    {
331      SynchronisableHeader syncHeader2(mem);
332      assert( this->getClassID() == syncHeader2.getClassID() );
333      assert( this->getCreatorID() == syncHeader2.getCreatorID() );
334      mem += SynchronisableHeader::getSize();
335      std::vector<SynchronisableVariableBase *>::iterator i;
336      for(i=syncList_.begin(); i!=syncList_.end(); ++i)
337      {
338        assert( mem <= data+syncHeader2.getDataSize()+SynchronisableHeader::getSize() ); // always make sure we don't exceed the datasize in our stream
339        (*i)->putData( mem, mode, forceCallback );
340      }
341      assert(mem == data+syncHeaderLight.getDataSize()+SynchronisableHeader::getSize() );
342    }
343    else
344    {
345      mem += SynchronisableHeaderLight::getSize();
346//       orxout(debug_output, context::network) << "objectID: " << this->objectID_ << endl;
347      while( mem < data+syncHeaderLight.getDataSize()+SynchronisableHeaderLight::getSize() )
348      {
349        VariableID varID = *(VariableID*)mem;
350//         orxout(debug_output, context::network) << "varID: " << varID << endl;
351        assert( varID < syncList_.size() );
352        mem += sizeof(VariableID);
353        syncList_[varID]->putData( mem, mode, forceCallback );
354      }
355      assert(mem == data+syncHeaderLight.getDataSize()+SynchronisableHeaderLight::getSize() );
356    }
357    return true;
358  }
359
360  /**
361  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
362  * @param id id of the gamestate
363  * @param mode same as getData
364  * @return amount of bytes
365  */
366  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode)
367  {
368    uint32_t tsize=SynchronisableHeader::getSize();
369    if (mode==0x0)
370      mode=state_;
371    if (!doSync(/*id, */mode))
372      return 0;
373    assert( mode==state_ );
374    tsize += this->dataSize_;
375    std::vector<SynchronisableVariableBase*>::iterator i;
376    for(i=stringList_.begin(); i!=stringList_.end(); ++i)
377    {
378      tsize += (*i)->getSize( mode );
379    }
380    return tsize;
381  }
382
383  /**
384   * This function determines, wheter the object should be saved to the bytestream (according to its syncmode/direction)
385   * @param mode Synchronisation mode (toclient, toserver or bidirectional)
386   * @return true/false
387   */
388  bool Synchronisable::doSync(/*int32_t id,*/ uint8_t mode)
389  {
390//     if(mode==0x0)
391//       mode=state_;
392    assert(mode!=0x0);
393    return ( (this->objectMode_ & mode)!=0 && (!syncList_.empty() ) );
394  }
395 
396  /**
397   * This function determines, wheter the object should accept data from the bytestream (according to its syncmode/direction)
398   * @param mode Synchronisation mode (toclient, toserver or bidirectional)
399   * @return true/false
400   */
401  bool Synchronisable::doReceive( uint8_t mode)
402  {
403    //return mode != this->objectMode_ || this->objectMode_ == ObjectDirection::Bidirectional;
404    return true;
405  }
406
407  /**
408   * This function sets the synchronisation mode of the object
409   * If set to 0x0 variables will not be synchronised at all
410   * If set to 0x1 variables will only be synchronised to the client
411   * If set to 0x2 variables will only be synchronised to the server
412   * If set to 0x3 variables will be synchronised bidirectionally (only if set so in registerVar)
413   * @param mode same as in registerVar
414   */
415  void Synchronisable::setSyncMode(uint8_t mode)
416  {
417    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
418    this->objectMode_=mode;
419  }
420
421  template <> void Synchronisable::registerVariable( std::string& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional)
422  {
423    SynchronisableVariableBase* sv;
424    if (bidirectional)
425      sv = new SynchronisableVariableBidirectional<std::string>(variable, mode, cb);
426    else
427      sv = new SynchronisableVariable<std::string>(variable, mode, cb);
428    syncList_.push_back(sv);
429    stringList_.push_back(sv);
430  }
431
432template <> void Synchronisable::unregisterVariable( std::string& variable )
433  {
434    bool unregistered_nonexistent_variable = true;
435    std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin();
436    while(it!=syncList_.end())
437    {
438      if( ((*it)->getReference()) == &variable )
439      {
440        delete (*it);
441        syncList_.erase(it);
442        unregistered_nonexistent_variable = false;
443        break;
444      }
445      else
446        ++it;
447    }
448    assert(unregistered_nonexistent_variable == false);
449   
450    it = stringList_.begin();
451    while(it!=stringList_.end())
452    {
453      if( ((*it)->getReference()) == &variable )
454      {
455        delete (*it);
456        stringList_.erase(it);
457        return;
458      }
459      else
460        ++it;
461    }
462    unregistered_nonexistent_variable = true;
463    assert(unregistered_nonexistent_variable == false); //if we reach this point something went wrong:
464    // the variable has not been registered before
465  }
466
467
468}
Note: See TracBrowser for help on using the repository browser.