Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/Synchronisable.cc @ 1742

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

compressing and diffing works now (also shipCache on client). server can't move while client connected. preparations for synchronise frequency of synchronisables

  • Property svn:eol-style set to native
File size: 11.4 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 <string>
44#include <iostream>
45#include <assert.h>
46
47#include "core/CoreIncludes.h"
48#include "core/BaseObject.h"
49// #include "core/Identifier.h"
50
51namespace network
52{
53
54
55  int Synchronisable::state_=0x1; // detemines wheter we are server (default) or client
56
57  /**
58  * Constructor:
59  * calls registarAllVariables, that has to be implemented by the inheriting classID
60  */
61  Synchronisable::Synchronisable(){
62    RegisterRootObject(Synchronisable);
63    static int idCounter=0;
64    datasize=0;
65    objectFrequency_=1;
66    objectID=idCounter++;
67    syncList = new std::list<synchronisableVariable *>;
68    //registerAllVariables();
69  }
70
71  Synchronisable::~Synchronisable(){
72    // delete callback function objects
73    if(!orxonox::Identifier::isCreatingHierarchy())
74      for(std::list<synchronisableVariable *>::iterator it = syncList->begin(); it!=syncList->end(); it++)
75        delete (*it)->callback;
76  }
77
78  bool Synchronisable::create(){
79    this->classID = this->getIdentifier()->getNetworkID();
80    COUT(4) << "creating synchronisable: setting classid from " << this->getIdentifier()->getName() << " to: " << classID << std::endl;
81    return true;
82  }
83
84  void Synchronisable::setClient(bool b){
85    if(b) // client
86      state_=0x2;
87    else  // server
88      state_=0x1;
89  }
90 
91  bool Synchronisable::fabricate(unsigned char*& mem, int mode)
92  {
93    unsigned int size, objectID, classID;
94    size = *(unsigned int *)mem;
95    objectID = *(unsigned int*)(mem+sizeof(unsigned int));
96    classID = *(unsigned int*)(mem+2*sizeof(unsigned int));
97   
98    if(size==3*sizeof(unsigned int)) //not our turn, dont do anything
99      return true;
100   
101    orxonox::Identifier* id = ID(classID);
102    if(!id){
103      COUT(3) << "We could not identify a new object; classid: " << classID << " uint: " << (unsigned int)classID << " objectID: " << objectID << " size: " << size << std::endl;
104      assert(0);
105      return false; // most probably the gamestate is corrupted
106    }
107    orxonox::BaseObject *bo = id->fabricate();
108    Synchronisable *no = dynamic_cast<Synchronisable *>(bo);
109    assert(no);
110    no->objectID=objectID;
111    no->classID=classID;
112    COUT(3) << "fabricate objectID: " << no->objectID << " classID: " << no->classID << std::endl;
113          // update data and create object/entity...
114    if( !no->updateData(mem, mode) ){
115      COUT(1) << "We couldn't update the object: " << objectID << std::endl;
116      return false;
117    }
118    if( !no->create() )
119    {
120      COUT(1) << "We couldn't manifest (create() ) the object: " << objectID << std::endl;
121      return false;
122    }
123    return true;
124  }
125
126  /**
127  * This function is used to register a variable to be synchronized
128  * also counts the total datasize needed to save the variables
129  * @param var pointer to the variable
130  * @param size size of the datatype the variable consists of
131  */
132  void Synchronisable::registerVar(void *var, int size, variableType t, int mode, NetworkCallbackBase *cb){
133    // create temporary synch.Var struct
134    synchronisableVariable *temp = new synchronisableVariable;
135    temp->size = size;
136    temp->var = var;
137    temp->mode = mode;
138    temp->type = t;
139    temp->callback = cb;
140    COUT(5) << "Syncronisable::registering var with size: " << temp->size << " and type: " << temp->type << std::endl;
141    // increase datasize
142    datasize+=sizeof(int)+size;
143    //std::cout << "push temp to syncList (at the bottom) " << datasize << std::endl;
144    COUT(5) << "Syncronisable::objectID: " << objectID << " this: " << this << " name: " << this->getIdentifier()->getName() << " networkID: " << this->getIdentifier()->getNetworkID() << std::endl;
145    syncList->push_back(temp);
146  }
147 
148  /**
149   * This function takes all SynchronisableVariables out of the Synchronisable and saves it into a syncData struct
150   * Difference to the above function:
151   * takes a pointer to already allocated memory (must have at least getSize bytes length)
152   * structure of the bitstream:
153   * (var1_size,var1,var2_size,var2,...)
154   * varx_size: size = sizeof(int)
155   * varx: size = varx_size
156   * @return data containing all variables and their sizes
157   */
158  bool Synchronisable::getData(unsigned char*& mem, unsigned int id, int mode){
159    //std::cout << "inside getData" << std::endl;
160    unsigned int tempsize = 0;
161    if(mode==0x0)
162      mode=state_;
163    if(classID==0)
164      COUT(3) << "classid 0 " << this->getIdentifier()->getName() << std::endl;
165    this->classID=this->getIdentifier()->getNetworkID(); // TODO: correct this
166    std::list<synchronisableVariable *>::iterator i;
167    unsigned int size;
168    size=getSize2(id, mode);
169   
170    // start copy header
171    memcpy(mem, &size, sizeof(unsigned int));
172    mem+=sizeof(unsigned int);
173    memcpy(mem, &(this->objectID), sizeof(unsigned int));
174    mem+=sizeof(unsigned int);
175    memcpy(mem, &(this->classID), sizeof(unsigned int));
176    mem+=sizeof(unsigned int);
177    tempsize+=12;
178    // end copy header
179   
180    //if this tick is we dont synchronise, then abort now
181    if(!isMyTick(id))
182      return true;
183   
184    COUT(5) << "Synchronisable getting data from objectID: " << objectID << " classID: " << classID << " length: " << size << std::endl;
185    // copy to location
186    for(i=syncList->begin(); i!=syncList->end(); ++i){
187      //(std::memcpy(retVal.data+n, (const void*)(&(i->size)), sizeof(int));
188      if( ((*i)->mode & mode) == 0 ){
189        COUT(5) << "not getting data: " << std::endl;
190        continue;  // this variable should only be received
191      }
192      switch((*i)->type){
193        case DATA:
194          memcpy( (void *)(mem), (void*)((*i)->var), (*i)->size);
195          mem+=(*i)->size;
196          tempsize+=(*i)->size;
197          break;
198        case STRING:
199          memcpy( (void *)(mem), (void *)&((*i)->size), sizeof(int) );
200          mem+=sizeof(int);
201          const char *data = ( ( *(std::string *) (*i)->var).c_str());
202          memcpy( mem, (void*)data, (*i)->size);
203          COUT(5) << "synchronisable: char: " << (const char *)(mem) << " data: " << data << " string: " << *(std::string *)((*i)->var) << std::endl;
204          mem+=(*i)->size;
205          tempsize+=(*i)->size + 4;
206          break;
207      }
208    }
209    assert(tempsize==size);
210    return true;
211  }
212
213 
214  /**
215   * This function takes a syncData struct and takes it to update the variables
216   * @param vars data of the variables
217   * @return true/false
218   */
219  bool Synchronisable::updateData(unsigned char*& mem, int mode){
220    unsigned char *data = mem;
221    if(mode==0x0)
222      mode=state_;
223    std::list<synchronisableVariable *>::iterator i;
224    if(syncList->empty()){
225      COUT(4) << "Synchronisable::updateData syncList is empty" << std::endl;
226      return false;
227    }
228   
229    // start extract header
230    unsigned int objectID, classID, size;
231    size = *(int *)mem;
232    mem+=sizeof(size);
233    objectID = *(int *)mem;
234    mem+=sizeof(objectID);
235    classID = *(int *)mem;
236    mem+=sizeof(classID);
237    // stop extract header
238    assert(this->objectID==objectID);
239    assert(this->classID==classID);
240    if(size==3*sizeof(unsigned int)) //if true, only the header is available
241      return true;
242      //assert(0);
243   
244    COUT(5) << "Synchronisable: objectID " << objectID << ", classID " << classID << " size: " << size << " synchronising data" << std::endl;
245    for(i=syncList->begin(); i!=syncList->end() && mem <= data+size; i++){
246      if( ((*i)->mode ^ mode) == 0 ){
247        COUT(5) << "synchronisable: not updating variable " << std::endl;
248        continue;  // this variable should only be set
249      }
250      COUT(5) << "Synchronisable: element size: " << (*i)->size << " type: " << (*i)->type << std::endl;
251      bool callback=false;
252      switch((*i)->type){
253        case DATA:
254          if((*i)->callback) // check whether this variable changed (but only if callback was set)
255            if(strncmp((char *)(*i)->var, (char *)mem, (*i)->size)!=0)
256              callback=true;
257          memcpy((void*)(*i)->var, mem, (*i)->size);
258          mem+=(*i)->size;
259          break;
260        case STRING:
261          (*i)->size = *(int *)mem;
262          COUT(5) << "string size: " << (*i)->size << std::endl;
263          mem+=sizeof(int);
264          if((*i)->callback) // check whether this string changed
265            if( *(std::string *)((*i)->var) != std::string((char *)mem) )
266              callback=true;
267          *((std::string *)((*i)->var)) = std::string((const char*)mem);
268          COUT(5) << "synchronisable: char: " << (const char*)mem << " string: " << std::string((const char*)mem) << std::endl;
269          mem += (*i)->size;
270          break;
271      }
272      // call the callback function, if defined
273      if(callback && (*i)->callback)
274        (*i)->callback->call();
275    }
276    return true;
277  }
278
279  /**
280  * This function returns the total amount of bytes needed by getData to save the whole content of the variables
281  * @return amount of bytes
282  */
283  int Synchronisable::getSize(unsigned int id, int mode){
284    if(!isMyTick(id))
285      return 0;
286    int tsize=0;
287    if(mode==0x0)
288      mode=state_;
289    std::list<synchronisableVariable *>::iterator i;
290    for(i=syncList->begin(); i!=syncList->end(); i++){
291      if( ((*i)->mode & mode) == 0 )
292        continue;  // this variable should only be received, so dont add its size to the send-size
293      switch((*i)->type){
294      case DATA:
295        tsize+=(*i)->size;
296        break;
297      case STRING:
298        tsize+=sizeof(int);
299        (*i)->size=((std::string *)(*i)->var)->length()+1;
300        COUT(5) << "String size: " << (*i)->size << std::endl;
301        tsize+=(*i)->size;
302        break;
303      }
304    }
305    return tsize;
306  }
307
308  /**
309   * This function returns the total amount of bytes needed by getData to save the whole content of the variables
310   * @return amount of bytes
311   */
312  int Synchronisable::getSize2(unsigned int id, int mode){
313    return sizeof(synchronisableHeader) + getSize( id, mode );
314  }
315 
316  bool Synchronisable::isMyTick(unsigned int id){
317//     return true;
318    return id==0 || id%objectFrequency_==objectID%objectFrequency_;
319  }
320 
321  bool Synchronisable::isMyData(unsigned char* mem)
322  {
323    unsigned int objectID, classID, size;
324    size = *(int *)mem;
325    mem+=sizeof(size);
326    objectID = *(int *)mem;
327    mem+=sizeof(objectID);
328    classID = *(int *)mem;
329    mem+=sizeof(classID);
330   
331    assert(classID == this->classID);
332    return (objectID == this->objectID);
333  }
334 
335  void Synchronisable::setBacksync(bool sync){
336    backsync_=sync;
337  }
338
339  bool Synchronisable::getBacksync(){
340    return backsync_;
341  }
342
343}
Note: See TracBrowser for help on using the repository browser.