Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2245 was 2245, checked in by scheusso, 15 years ago

most coding is done, still testing now
types should get transfered in platform independent formats now

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