Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/menuanimations/src/libraries/network/synchronisable/Synchronisable.cc @ 7338

Last change on this file since 7338 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
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->setObjectID( idCounter++ );
58    }
59    else
60    {
61      objectID_=OBJECTID_UNKNOWN;
62    }
63    classID_ = static_cast<uint32_t>(-1);
64   
65    // set dataSize to 0
66    this->dataSize_ = 0;
67    // set standard priority
68    this->setPriority( Priority::Normal );
69
70    // get creator id
71    if( creator )
72      this->creatorID_ = creator->getSceneID();
73    else
74      this->creatorID_ = OBJECTID_UNKNOWN;
75
76    /*searchcreatorID:
77    if (creator)
78    {
79        Synchronisable* synchronisable_creator = orxonox_cast<Synchronisable*>(creator);
80        if (synchronisable_creator && synchronisable_creator->objectMode_)
81        {
82            this->creatorID = synchronisable_creator->getScene()->getObjectID();
83        }
84        else if (creator != creator->getCreator())
85        {
86            creator = creator->getCreator();
87            goto searchcreatorID;
88        }
89    }*/
90  }
91
92  /**
93   * Destructor:
94   * Delete all callback objects and remove objectID_ from the objectMap_
95   */
96  Synchronisable::~Synchronisable(){
97    // delete callback function objects
98    if(!Identifier::isCreatingHierarchy()){
99      // remove object from the static objectMap
100      if (this->objectMode_ != 0x0 && (Host::running() && Host::isServer()))
101        deletedObjects_.push(objectID_);
102    }
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();
108    std::map<uint32_t, Synchronisable*>::iterator it;
109    it = objectMap_.find(objectID_);
110    if (it != objectMap_.end())
111      objectMap_.erase(it);
112
113  }
114
115
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   */
120  void Synchronisable::setClient(bool b){
121    if(b) // client
122      state_=0x2;
123    else  // server
124      state_=0x1;
125  }
126
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   */
134  Synchronisable *Synchronisable::fabricate(uint8_t*& mem, uint8_t mode)
135  {
136    SynchronisableHeader header(mem);
137
138    if(!header.isDataAvailable())
139    {
140      mem += header.getDataSize();
141      return 0;
142    }
143
144    COUT(4) << "fabricating object with id: " << header.getObjectID() << std::endl;
145
146    Identifier* id = ClassByID(header.getClassID());
147    if (!id)
148    {
149        for(int i = 0; i<160; i++)
150            COUT(0) << "classid: " << i << " identifier: " << ClassByID(i) << endl;
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    }
155    assert(id);
156    BaseObject* creator = 0;
157    if (header.getCreatorID() != OBJECTID_UNKNOWN)
158    {
159      Synchronisable* synchronisable_creator = Synchronisable::getSynchronisable(header.getCreatorID());
160      if (!synchronisable_creator)
161      {
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) ^^
164        return 0;
165      }
166      else
167        creator = orxonox_cast<BaseObject*>(synchronisable_creator);
168    }
169    assert(getSynchronisable(header.getObjectID())==0);   //make sure no object with this id exists
170    BaseObject *bo = id->fabricate(creator);
171    assert(bo);
172    Synchronisable *no = orxonox_cast<Synchronisable*>(bo);
173    assert(no);
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;
181          // update data and create object/entity...
182    bool b = no->updateData(mem, mode, true);
183    assert(b);
184    if (b)
185    {
186//        b = no->create();
187        assert(b);
188    }
189    return no;
190  }
191
192
193  /**
194   * Finds and deletes the Synchronisable with the appropriate objectID_
195   * @param objectID_ objectID_ of the Synchronisable
196   * @return true/false
197   */
198  bool Synchronisable::deleteObject(uint32_t objectID_){
199    if(!getSynchronisable(objectID_))
200      return false;
201    assert(getSynchronisable(objectID_)->objectID_==objectID_);
202    Synchronisable *s = getSynchronisable(objectID_);
203    if(s)
204      s->destroy(); // or delete?
205    else
206      return false;
207    return true;
208  }
209
210  /**
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_
214   */
215  Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID_){
216    std::map<uint32_t, Synchronisable*>::iterator it1;
217    it1 = objectMap_.find(objectID_);
218    if (it1 != objectMap_.end())
219      return it1->second;
220
221//     ObjectList<Synchronisable>::iterator it;
222//     for(it = ObjectList<Synchronisable>::begin(); it; ++it){
223//       if( it->getObjectID()==objectID_ ){
224//         objectMap_[objectID_] = *it;
225//         return *it;
226//       }
227//     }
228    // if the objects not in the map it should'nt exist at all anymore
229    return NULL;
230  }
231
232
233  /**
234   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID_ and classID_ to the given memory
235   * takes a pointer to already allocated memory (must have at least getSize bytes length)
236   * structure of the bitstream:
237   * |totalsize,objectID_,classID_,var1,var2,string1_length,string1,var3,...|
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
245   * @return true: if !doSync or if everything was successfully saved
246   */
247  uint32_t Synchronisable::getData(uint8_t*& mem, int32_t id, uint8_t mode){
248    if(mode==0x0)
249      mode=state_;
250    //if this tick is we dont synchronise, then abort now
251    if(!doSync(id, mode))
252      return 0;
253    uint32_t tempsize = 0;
254#ifndef NDEBUG
255    if (this->classID_==0)
256      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
257#endif
258
259    if (this->classID_ == static_cast<uint32_t>(-1))
260        this->classID_ = this->getIdentifier()->getNetworkID();
261
262    assert(ClassByID(this->classID_));
263    assert(this->classID_==this->getIdentifier()->getNetworkID());
264    assert(this->objectID_!=OBJECTID_UNKNOWN);
265    std::vector<SynchronisableVariableBase*>::iterator i;
266
267    // start copy header
268    SynchronisableHeader header(mem);
269    mem += SynchronisableHeader::getSize();
270    // end copy header
271
272
273    COUT(5) << "Synchronisable getting data from objectID_: " << objectID_ << " classID_: " << classID_ << std::endl;
274    // copy to location
275    for(i=syncList.begin(); i!=syncList.end(); ++i){
276      tempsize += (*i)->getData( mem, mode );
277      //tempsize += (*i)->getSize( mode );
278    }
279   
280    tempsize += SynchronisableHeader::getSize();
281    header.setObjectID( this->objectID_ );
282    header.setCreatorID( this->creatorID_ );
283    header.setClassID( this->classID_ );
284    header.setDataAvailable( true );
285    header.setDataSize( tempsize );
286   
287#ifndef NDEBUG
288    uint32_t size;
289    size=getSize(id, mode);
290    assert(tempsize==size);
291#endif
292    return tempsize;
293  }
294
295
296  /**
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
300   * @return true/false
301   */
302  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback){
303    if(mode==0x0)
304      mode=state_;
305    std::vector<SynchronisableVariableBase *>::iterator i;
306    if(syncList.empty()){
307      assert(0);
308      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
309      return false;
310    }
311
312    uint8_t* data=mem;
313    // start extract header
314    SynchronisableHeader syncHeader(mem);
315    assert(syncHeader.getObjectID()==this->objectID_);
316    assert(syncHeader.getCreatorID()==this->creatorID_);
317    assert(syncHeader.getClassID()==this->classID_);
318    if(syncHeader.isDataAvailable()==false){
319      mem += syncHeader.getDataSize();
320      return true;
321    }
322
323    mem += SynchronisableHeader::getSize();
324    // stop extract header
325
326    //COUT(5) << "Synchronisable: objectID_ " << syncHeader.getObjectID() << ", classID_ " << syncHeader.getClassID() << " size: " << syncHeader.getDataSize() << " synchronising data" << std::endl;
327    for(i=syncList.begin(); i!=syncList.end(); i++)
328    {
329      assert( mem <= data+syncHeader.getDataSize() ); // always make sure we don't exceed the datasize in our stream
330      (*i)->putData( mem, mode, forceCallback );
331    }
332    assert(mem == data+syncHeader.getDataSize());
333    return true;
334  }
335
336  /**
337  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
338  * @param id id of the gamestate
339  * @param mode same as getData
340  * @return amount of bytes
341  */
342  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode){
343    int tsize=SynchronisableHeader::getSize();
344    if (mode==0x0)
345      mode=state_;
346    if (!doSync(id, mode))
347      return 0;
348    assert( mode==state_ );
349    tsize += this->dataSize_;
350    std::vector<SynchronisableVariableBase*>::iterator i;
351    for(i=stringList.begin(); i!=stringList.end(); ++i){
352      tsize += (*i)->getSize( mode );
353    }
354    return tsize;
355  }
356
357  /**
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
361   */
362  bool Synchronisable::doSync(int32_t id, uint8_t mode){
363    if(mode==0x0)
364      mode=state_;
365    return ( (this->objectMode_ & mode)!=0 && (!syncList.empty() ) );
366  }
367
368  /**
369   * This function looks at the header located in the bytestream and checks wheter objectID_ and classID_ match with the Synchronisables ones
370   * @param mem pointer to the bytestream
371   */
372  bool Synchronisable::isMyData(uint8_t* mem)
373  {
374    SynchronisableHeader header(mem);
375    assert(header.getObjectID()==this->objectID_);
376    return header.isDataAvailable();
377  }
378
379  /**
380   * This function sets the synchronisation mode of the object
381   * If set to 0x0 variables will not be synchronised at all
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   */
387  void Synchronisable::setSyncMode(uint8_t mode){
388    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
389    this->objectMode_=mode;
390  }
391
392
393}
Note: See TracBrowser for help on using the repository browser.