Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/network/synchronisable/Synchronisable.cc @ 3171

Last change on this file since 3171 was 3088, checked in by scheusso, 16 years ago

fix in Projectile (there was no createFactory) and some additional debugging
and in hubtimer (only on server now)
and in lightninggun (material is synchronised)

  • Property svn:eol-style set to native
File size: 12.5 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 <cassert>
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 dataSize to 0
70    this->dataSize_ = 0;
71    // set standard priority
72    this->setPriority( priority::normal );
73
74    // get creator id
75    this->creatorID = OBJECTID_UNKNOWN;
76
77    searchcreatorID:
78    if (creator)
79    {
80        Synchronisable* synchronisable_creator = dynamic_cast<Synchronisable*>(creator);
81        if (synchronisable_creator && synchronisable_creator->objectMode_)
82        {
83            this->creatorID = synchronisable_creator->getObjectID();
84        }
85        else if (creator != creator->getCreator())
86        {
87            creator = creator->getCreator();
88            goto searchcreatorID;
89        }
90    }
91  }
92
93  /**
94   * Destructor:
95   * Delete all callback objects and remove objectID from the objectMap_
96   */
97  Synchronisable::~Synchronisable(){
98    // delete callback function objects
99    if(!Identifier::isCreatingHierarchy()){
100      for(std::vector<SynchronisableVariableBase*>::iterator it = syncList.begin(); it!=syncList.end(); it++)
101        delete (*it);
102      if (this->objectMode_ != 0x0 && (Host::running() && Host::isServer()))
103        deletedObjects_.push(objectID);
104    }
105    std::map<uint32_t, Synchronisable*>::iterator it;
106    it = objectMap_.find(objectID);
107    if (it != objectMap_.end())
108      objectMap_.erase(it);
109
110  }
111
112
113  /**
114   * This function sets the internal mode for synchronisation
115   * @param b true if this object is located on a client or on a server
116   */
117  void Synchronisable::setClient(bool b){
118    if(b) // client
119      state_=0x2;
120    else  // server
121      state_=0x1;
122  }
123
124  /**
125   * This function fabricated a new synchrnisable (and children of it), sets calls updateData and create
126   * After calling this function the mem pointer will be increased by the size of the needed data
127   * @param mem pointer to where the appropriate data is located
128   * @param mode defines the mode, how the data should be loaded
129   * @return pointer to the newly created synchronisable
130   */
131  Synchronisable *Synchronisable::fabricate(uint8_t*& mem, uint8_t mode)
132  {
133    SynchronisableHeader header(mem);
134
135    if(!header.isDataAvailable())
136    {
137      mem += header.getDataSize();
138      return 0;
139    }
140
141    COUT(4) << "fabricating object with id: " << header.getObjectID() << std::endl;
142
143    Identifier* id = ClassByID(header.getClassID());
144    if (!id)
145    {
146        for(int i = 0; i<160; i++)
147            COUT(0) << "classid: " << i << " identifier: " << ClassByID(i) << endl;
148        COUT(0) << "Assertion failed: id" << std::endl;
149        COUT(0) << "Possible reason for this error: Client received a synchronizable object whose class has no factory." << std::endl;
150        abort();
151    }
152    assert(id);
153    BaseObject* creator = 0;
154    if (header.getCreatorID() != OBJECTID_UNKNOWN)
155    {
156      Synchronisable* synchronisable_creator = Synchronisable::getSynchronisable(header.getCreatorID());
157      if (!synchronisable_creator)
158      {
159        mem += header.getDataSize(); //.TODO: this suckz.... remove size from header
160        assert(0); // TODO: uncomment this if we have a clean objecthierarchy (with destruction of children of objects) ^^
161        return 0;
162      }
163      else
164        creator = dynamic_cast<BaseObject*>(synchronisable_creator);
165    }
166    assert(getSynchronisable(header.getObjectID())==0);   //make sure no object with this id exists
167    BaseObject *bo = id->fabricate(creator);
168    assert(bo);
169    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
170    assert(no);
171    no->objectID=header.getObjectID();
172    no->creatorID=header.getCreatorID(); //TODO: remove this
173    no->classID=header.getClassID();
174    COUT(4) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
175          // update data and create object/entity...
176    bool b = no->updateData(mem, mode, true);
177    assert(b);
178    if (b)
179    {
180//        b = no->create();
181        assert(b);
182    }
183    return no;
184  }
185
186
187  /**
188   * Finds and deletes the Synchronisable with the appropriate objectID
189   * @param objectID objectID of the Synchronisable
190   * @return true/false
191   */
192  bool Synchronisable::deleteObject(uint32_t objectID){
193    if(!getSynchronisable(objectID))
194      return false;
195    assert(getSynchronisable(objectID)->objectID==objectID);
196    Synchronisable *s = getSynchronisable(objectID);
197    if(s)
198      delete s;
199    else
200      return false;
201    return true;
202  }
203
204  /**
205   * This function looks up the objectID in the objectMap_ and returns a pointer to the right Synchronisable
206   * @param objectID objectID of the Synchronisable
207   * @return pointer to the Synchronisable with the objectID
208   */
209  Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID){
210    std::map<uint32_t, Synchronisable*>::iterator it1;
211    it1 = objectMap_.find(objectID);
212    if (it1 != objectMap_.end())
213      return it1->second;
214
215    ObjectList<Synchronisable>::iterator it;
216    for(it = ObjectList<Synchronisable>::begin(); it; ++it){
217      if( it->getObjectID()==objectID ){
218        objectMap_[objectID] = *it;
219        return *it;
220      }
221    }
222    return NULL;
223  }
224
225
226  /**
227   * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID and classID to the given memory
228   * takes a pointer to already allocated memory (must have at least getSize bytes length)
229   * structure of the bitstream:
230   * |totalsize,objectID,classID,var1,var2,string1_length,string1,var3,...|
231   * length of varx: size saved int syncvarlist
232   * @param mem pointer to allocated memory with enough size
233   * @param id gamestateid of the gamestate to be saved (important for priorities)
234   * @param mode defines the direction in which the data will be send/received
235   *             0x1: server->client
236   *             0x2: client->server (not recommended)
237   *             0x3: bidirectional
238   * @return true: if !doSync or if everything was successfully saved
239   */
240  uint32_t Synchronisable::getData(uint8_t*& mem, int32_t id, uint8_t mode){
241    if(mode==0x0)
242      mode=state_;
243    //if this tick is we dont synchronise, then abort now
244    if(!doSync(id, mode))
245      return 0;
246    uint32_t tempsize = 0;
247    if (this->classID==0)
248      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
249
250    if (this->classID == static_cast<uint32_t>(-1))
251        this->classID = this->getIdentifier()->getNetworkID();
252
253    assert(ClassByID(this->classID));
254    assert(this->classID==this->getIdentifier()->getNetworkID());
255    std::vector<SynchronisableVariableBase*>::iterator i;
256
257    // start copy header
258    SynchronisableHeader header(mem);
259    mem += SynchronisableHeader::getSize();
260    // end copy header
261
262
263    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << std::endl;
264    // copy to location
265    for(i=syncList.begin(); i!=syncList.end(); ++i){
266      tempsize += (*i)->getData( mem, mode );
267      //tempsize += (*i)->getSize( mode );
268    }
269   
270    tempsize += SynchronisableHeader::getSize();
271    header.setObjectID( this->objectID );
272    header.setCreatorID( this->creatorID );
273    header.setClassID( this->classID );
274    header.setDataAvailable( true );
275    header.setDataSize( tempsize );
276   
277#ifndef NDEBUG
278    uint32_t size;
279    size=getSize(id, mode);
280    assert(tempsize==size);
281#endif
282    return tempsize;
283  }
284
285
286  /**
287   * This function takes a bytestream and loads the data into the registered variables
288   * @param mem pointer to the bytestream
289   * @param mode same as in getData
290   * @return true/false
291   */
292  bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback){
293    if(mode==0x0)
294      mode=state_;
295    std::vector<SynchronisableVariableBase *>::iterator i;
296    if(syncList.empty()){
297      assert(0);
298      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
299      return false;
300    }
301
302    uint8_t* data=mem;
303    // start extract header
304    SynchronisableHeader syncHeader(mem);
305    assert(syncHeader.getObjectID()==this->objectID);
306    assert(syncHeader.getCreatorID()==this->creatorID);
307    assert(syncHeader.getClassID()==this->classID);
308    if(syncHeader.isDataAvailable()==false){
309      mem += syncHeader.getDataSize();
310      return true;
311    }
312
313    mem += SynchronisableHeader::getSize();
314    // stop extract header
315
316    //COUT(5) << "Synchronisable: objectID " << syncHeader.getObjectID() << ", classID " << syncHeader.getClassID() << " size: " << syncHeader.getDataSize() << " synchronising data" << std::endl;
317    for(i=syncList.begin(); i!=syncList.end(); i++)
318    {
319      assert( mem <= data+syncHeader.getDataSize() ); // always make sure we don't exceed the datasize in our stream
320      (*i)->putData( mem, mode, forceCallback );
321    }
322    assert(mem == data+syncHeader.getDataSize());
323    return true;
324  }
325
326  /**
327  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
328  * @param id id of the gamestate
329  * @param mode same as getData
330  * @return amount of bytes
331  */
332  uint32_t Synchronisable::getSize(int32_t id, uint8_t mode){
333    int tsize=SynchronisableHeader::getSize();
334    if (mode==0x0)
335      mode=state_;
336    if (!doSync(id, mode))
337      return 0;
338    assert( mode==state_ );
339    tsize += this->dataSize_;
340    std::vector<SynchronisableVariableBase*>::iterator i;
341    for(i=stringList.begin(); i!=stringList.end(); ++i){
342      tsize += (*i)->getSize( mode );
343    }
344    return tsize;
345  }
346
347  /**
348   * This function determines, wheter the object should be saved to the bytestream (according to its syncmode/direction)
349   * @param id gamestate id
350   * @return true/false
351   */
352  bool Synchronisable::doSync(int32_t id, uint8_t mode){
353    if(mode==0x0)
354      mode=state_;
355    return ( (objectMode_&mode)!=0 && (!syncList.empty() ) );
356  }
357
358  /**
359   * This function looks at the header located in the bytestream and checks wheter objectID and classID match with the Synchronisables ones
360   * @param mem pointer to the bytestream
361   */
362  bool Synchronisable::isMyData(uint8_t* mem)
363  {
364    SynchronisableHeader header(mem);
365    assert(header.getObjectID()==this->objectID);
366    return header.isDataAvailable();
367  }
368
369  /**
370   * This function sets the synchronisation mode of the object
371   * If set to 0x0 variables will not be synchronised at all
372   * If set to 0x1 variables will only be synchronised to the client
373   * If set to 0x2 variables will only be synchronised to the server
374   * If set to 0x3 variables will be synchronised bidirectionally (only if set so in registerVar)
375   * @param mode same as in registerVar
376   */
377  void Synchronisable::setObjectMode(uint8_t mode){
378    assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3);
379    objectMode_=mode;
380  }
381
382
383}
Note: See TracBrowser for help on using the repository browser.