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
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 <cstring>
34#include <string>
35#include <iostream>
36#include <assert.h>
37
38#include "core/CoreIncludes.h"
39#include "core/BaseObject.h"
40// #include "core/Identifier.h"
41
42#include "network/Host.h"
43namespace orxonox
44{
45
46  std::map<uint32_t, Synchronisable *> Synchronisable::objectMap_;
47  std::queue<uint32_t> Synchronisable::deletedObjects_;
48
49  uint8_t Synchronisable::state_=0x1; // detemines wheter we are server (default) or client
50
51  /**
52  * Constructor:
53  * Initializes all Variables and sets the right objectID
54  */
55  Synchronisable::Synchronisable(BaseObject* creator){
56    RegisterRootObject(Synchronisable);
57    static uint32_t idCounter=0;
58    objectMode_=0x1; // by default do not send data to server
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;
67    classID = static_cast<uint32_t>(-1);
68
69    // set standard priority
70    this->setPriority( priority::normal );
71
72    // get creator id
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    }
89  }
90
91  /**
92   * Destructor:
93   * Delete all callback objects and remove objectID from the objectMap_
94   */
95  Synchronisable::~Synchronisable(){
96    // delete callback function objects
97    if(!Identifier::isCreatingHierarchy()){
98      for(std::list<SynchronisableVariableBase*>::iterator it = syncList.begin(); it!=syncList.end(); it++)
99        delete (*it);
100      if (this->objectMode_ != 0x0 && (Host::running() && Host::isServer()))
101        deletedObjects_.push(objectID);
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    }
107    std::map<uint32_t, Synchronisable*>::iterator it;
108    it = objectMap_.find(objectID);
109    if (it != objectMap_.end())
110      objectMap_.erase(it);
111
112    //HACK HACK HACK HACK HACK HACK
113    // this hack ensures that children of this object also get destroyed
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
124  }
125
126
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   */
131  void Synchronisable::setClient(bool b){
132    if(b) // client
133      state_=0x2;
134    else  // server
135      state_=0x1;
136  }
137
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   */
145  Synchronisable *Synchronisable::fabricate(uint8_t*& mem, uint8_t mode)
146  {
147    SynchronisableHeader header(mem);
148
149    if(!header.isDataAvailable())
150    {
151      mem += header.getDataSize();
152      return 0;
153    }
154
155    COUT(4) << "fabricating object with id: " << header.getObjectID() << std::endl;
156
157    Identifier* id = ClassByID(header.getClassID());
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    }
164    assert(id);
165    BaseObject* creator = 0;
166    if (header.getCreatorID() != OBJECTID_UNKNOWN)
167    {
168      Synchronisable* synchronisable_creator = Synchronisable::getSynchronisable(header.getCreatorID());
169      if (!synchronisable_creator)
170      {
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) ^^
173        return 0;
174      }
175      else
176        creator = dynamic_cast<BaseObject*>(synchronisable_creator);
177    }
178    assert(getSynchronisable(header.getObjectID())==0);   //make sure no object with this id exists
179    BaseObject *bo = id->fabricate(creator);
180    assert(bo);
181    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
182    assert(no);
183    no->objectID=header.getObjectID();
184    no->creatorID=header.getCreatorID(); //TODO: remove this
185    no->classID=header.getClassID();
186    COUT(4) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
187          // update data and create object/entity...
188    bool b = no->updateData(mem, mode, true);
189    assert(b);
190    if (b)
191    {
192//        b = no->create();
193        assert(b);
194    }
195    return no;
196  }
197
198
199  /**
200   * Finds and deletes the Synchronisable with the appropriate objectID
201   * @param objectID objectID of the Synchronisable
202   * @return true/false
203   */
204  bool Synchronisable::deleteObject(uint32_t objectID){
205//     assert(getSynchronisable(objectID));
206    if(!getSynchronisable(objectID))
207      return false;
208    assert(getSynchronisable(objectID)->objectID==objectID);
209//     delete objectMap_[objectID];
210    Synchronisable *s = getSynchronisable(objectID);
211    if(s)
212      delete s;
213    else
214      return false;
215    return true;
216  }
217
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   */
223  Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID){
224    std::map<uint32_t, Synchronisable*>::iterator it1;
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      }
235    }
236    return NULL;
237  }
238
239
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
245  * @param t the type of the variable (DATA or STRING
246  * @param mode same as in getData
247  * @param cb callback object that should get called, if the value of the variable changes
248  */
249
250/*  void Synchronisable::registerVariable(void *var, int size, variableType t, uint8_t mode, NetworkCallbackBase *cb){
251    assert( mode==variableDirection::toclient || mode==variableDirection::toserver || mode==variableDirection::serverMaster || mode==variableDirection::clientMaster);
252    // create temporary synch.Var struct
253    synchronisableVariable *temp = new synchronisableVariable;
254    temp->size = size;
255    temp->var = var;
256    temp->mode = mode;
257    temp->type = t;
258    temp->callback = cb;
259    if( ( mode & variableDirection::bidirectional ) )
260    {
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      }
270      temp->varReference = 0;
271    }
272    COUT(5) << "Syncronisable::registering var with size: " << temp->size << " and type: " << temp->type << std::endl;
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);
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
283  }*/
284
285
286  /**
287   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID and classID to the given memory
288   * takes a pointer to already allocated memory (must have at least getSize bytes length)
289   * structure of the bitstream:
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
298   * @return true: if !doSync or if everything was successfully saved
299   */
300  bool Synchronisable::getData(uint8_t*& mem, int32_t id, uint8_t mode){
301    if(mode==0x0)
302      mode=state_;
303    //if this tick is we dont synchronise, then abort now
304    if(!doSync(id, mode))
305      return true;
306    //std::cout << "inside getData" << std::endl;
307    uint32_t tempsize = 0;
308    if (this->classID==0)
309      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
310
311    if (this->classID == static_cast<uint32_t>(-1))
312        this->classID = this->getIdentifier()->getNetworkID();
313
314    assert(this->classID==this->getIdentifier()->getNetworkID());
315//     this->classID=this->getIdentifier()->getNetworkID(); // TODO: correct this
316    std::list<SynchronisableVariableBase*>::iterator i;
317    uint32_t size;
318    size=getSize(id, mode);
319
320    // start copy header
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();
329    // end copy header
330
331
332    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << " length: " << size << std::endl;
333    // copy to location
334    for(i=syncList.begin(); i!=syncList.end(); ++i){
335      (*i)->getData( mem, mode );
336      tempsize += (*i)->getSize( mode );
337    }
338    assert(tempsize==size);
339    return true;
340  }
341
342
343  /**
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
347   * @return true/false
348   */
349  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback){
350    if(mode==0x0)
351      mode=state_;
352    std::list<SynchronisableVariableBase *>::iterator i;
353    //assert(objectMode_!=0x0);
354    //assert( (mode ^ objectMode_) != 0);
355    if(syncList.empty()){
356      assert(0);
357      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
358      return false;
359    }
360
361    uint8_t* data=mem;
362    // start extract header
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();
369      return true;
370    }
371
372    mem += SynchronisableHeader::getSize();
373    // stop extract header
374
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++)
377    {
378      assert( mem <= data+syncHeader.getDataSize() ); // always make sure we don't exceed the datasize in our stream
379      (*i)->putData( mem, mode, forceCallback );
380    }
381    assert(mem == data+syncHeader.getDataSize());
382    return true;
383  }
384
385  /**
386  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
387  * @param id id of the gamestate
388  * @param mode same as getData
389  * @return amount of bytes
390  */
391  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode){
392    int tsize=SynchronisableHeader::getSize();
393    if(mode==0x0)
394      mode=state_;
395    if(!doSync(id, mode))
396      return 0;
397    std::list<SynchronisableVariableBase*>::iterator i;
398    for(i=syncList.begin(); i!=syncList.end(); i++){
399      tsize += (*i)->getSize( mode );
400    }
401    return tsize;
402  }
403
404  /**
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
408   */
409  bool Synchronisable::doSync(int32_t id, uint8_t mode){
410    if(mode==0x0)
411      mode=state_;
412    return ( (objectMode_&mode)!=0 && (!syncList.empty() ) );
413  }
414
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)
420  {
421    SynchronisableHeader header(mem);
422    assert(header.getObjectID()==this->objectID);
423    return header.isDataAvailable();
424  }
425
426  /**
427   * This function sets the synchronisation mode of the object
428   * If set to 0x0 variables will not be synchronised at all
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   */
434  void Synchronisable::setObjectMode(uint8_t mode){
435    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
436    objectMode_=mode;
437  }
438
439
440}
Note: See TracBrowser for help on using the repository browser.