Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/netp5/src/network/synchronisable/Synchronisable.cc @ 3211

Last change on this file since 3211 was 3211, checked in by rgrieder, 15 years ago

Moved PacketFlag and added includes for memcpy() and abort() (Mingw didn't seem to care).

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