Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/network/synchronisable/Synchronisable.cc @ 2961

Last change on this file since 2961 was 2911, checked in by landauf, 16 years ago

Merged r1-2096 of questsystem5 back to trunk

I hope there weren't more "hidden merge changes" in r2909 than the one in OverlayGroup (removeElement) (and related to this the adjustments in NotificationQueue).

The corresponding media commit seems not yet to be done, but it doesn't break the build.

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