Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/network/synchronisable/Synchronisable.cc @ 2563

Last change on this file since 2563 was 2540, checked in by rgrieder, 16 years ago

Added comments to the WorldEntity except for the non physics section of the header file (going to do that some time later).

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