Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network64/src/network/synchronisable/Synchronisable.cc @ 2312

Last change on this file since 2312 was 2309, checked in by scheusso, 16 years ago

made some adjustments mostly to the networkid (classid) in order to have it platform independent

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