Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/libraries/network/packet/Gamestate.cc @ 8829

Last change on this file since 8829 was 8807, checked in by landauf, 13 years ago

Replaced COUT with orxout in network library. Tried to set levels and contexts in a more or less useful way, but not really optimized. Used contexts network, packets, and master_server.
Please use endl instead of \n in the future (@smerkli) ;)

  • Property svn:eol-style set to native
File size: 26.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 *      Oliver Scheuss
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Gamestate.h"
30
31#include <zlib.h>
32
33#include "util/Output.h"
34#include "util/OrxAssert.h"
35#include "core/GameMode.h"
36#include "core/ObjectList.h"
37#include "network/synchronisable/Synchronisable.h"
38#include "network/GamestateHandler.h"
39#include "network/Host.h"
40
41namespace orxonox {
42
43namespace packet {
44
45#define GAMESTATE_START(data) (data + GamestateHeader::getSize())
46
47// #define PACKET_FLAG_GAMESTATE  PacketFlag::Reliable
48#define PACKET_FLAG_GAMESTATE  0
49
50inline bool memzero( uint8_t* data, uint32_t datalength)
51{
52  uint64_t* d = (uint64_t*)data;
53
54  for( unsigned int i=0; i<datalength/8; i++ )
55  {
56    if( *(d+i) != 0 )
57      return false;
58  }
59  // now process the rest (when datalength isn't a multiple of 4)
60  for( unsigned int j = 8*(datalength/8); j<datalength; j++ )
61  {
62    if( *(data+j) != 0 )
63      return false;
64  }
65  return true;
66}
67
68
69Gamestate::Gamestate():
70  header_()
71{
72  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
73}
74
75
76Gamestate::Gamestate(uint8_t *data, unsigned int clientID):
77  Packet(data, clientID), header_(data)
78{
79  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
80}
81
82
83Gamestate::Gamestate(uint8_t *data):
84  header_(data)
85{
86  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
87  data_ = data;
88}
89
90
91Gamestate::Gamestate(const Gamestate& g) :
92  Packet( *(Packet*)&g ), header_(this->data_), nrOfVariables_(0)
93{
94  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
95  sizes_ = g.sizes_;
96}
97
98
99Gamestate::~Gamestate()
100{
101}
102
103
104bool Gamestate::collectData(int id, uint8_t mode)
105{
106  uint32_t tempsize=0, currentsize=0;
107  assert(data_==0);
108  uint32_t size = calcGamestateSize(id, mode);
109
110  orxout(verbose_more, context::packets) << "G.ST.Man: producing gamestate with id: " << id << endl;
111  if(size==0)
112    return false;
113  data_ = new uint8_t[size + GamestateHeader::getSize()];
114  if(!data_)
115  {
116    orxout(internal_warning, context::packets) << "GameStateManager: could not allocate memory" << endl;
117    return false;
118  }
119
120  // tell the gamestate header where to store the data
121  header_.setData(this->data_);
122
123  //start collect data synchronisable by synchronisable
124  uint8_t *mem = data_; // in this stream store all data of the variables and the headers of the synchronisable
125  mem += GamestateHeader::getSize();
126  ObjectList<Synchronisable>::iterator it;
127  for(it = ObjectList<Synchronisable>::begin(); it; ++it)
128  {
129
130//     tempsize=it->getSize(id, mode);
131
132    tempsize = it->getData(mem, this->sizes_, id, mode);
133    if ( tempsize != 0 )
134      dataVector_.push_back( obj(it->getObjectID(), it->getCreatorID(), tempsize, mem-data_) );
135
136#ifndef NDEBUG
137    if(currentsize+tempsize > size)
138    {
139      assert(0); // if we don't use multithreading this part shouldn't be neccessary
140      // start allocate additional memory
141      orxout(internal_info, context::packets) << "Gamestate: need additional memory" << endl;
142      ObjectList<Synchronisable>::iterator temp = it;
143      uint32_t addsize=tempsize;
144      while(++temp)
145        addsize+=temp->getSize(id, mode);
146      data_ = (uint8_t *)realloc(data_, GamestateHeader::getSize() + currentsize + addsize);
147      if(!data_)
148        return false;
149      size = currentsize+addsize;
150    }// stop allocate additional memory
151#endif
152//     if(!it->getData(mem, id, mode))
153//       return false; // mem pointer gets automatically increased because of call by reference
154    // increase size counter by size of current synchronisable
155    currentsize+=tempsize;
156  }
157
158
159  //start write gamestate header
160  header_.setDataSize( currentsize );
161  header_.setCompSize( 0 );
162  header_.setID( id );
163  header_.setBaseID( GAMESTATEID_INITIAL );
164  header_.setDiffed( false );
165  header_.setComplete( true );
166  header_.setCompressed( false );
167  //stop write gamestate header
168
169  orxout(verbose_more, context::packets) << "Gamestate: Gamestate size: " << currentsize << endl;
170  orxout(verbose_more, context::packets) << "Gamestate: 'estimated' (and corrected) Gamestate size: " << size << endl;
171  return true;
172}
173
174
175bool Gamestate::spreadData(uint8_t mode)
176{
177  orxout(verbose_more, context::packets) << "processing gamestate with id " << header_.getID() << endl;
178  assert(data_);
179  assert(!header_.isCompressed());
180  uint8_t *mem=data_+GamestateHeader::getSize();
181  Synchronisable *s;
182 
183  // update the data of the objects we received
184  while(mem < data_+GamestateHeader::getSize()+header_.getDataSize())
185  {
186    SynchronisableHeader objectheader(mem);
187
188    s = Synchronisable::getSynchronisable( objectheader.getObjectID() );
189    if(!s)
190    {
191      if (!GameMode::isMaster())
192      {
193        Synchronisable::fabricate(mem, mode);
194      }
195      else
196      {
197//         orxout(verbose, context::packets) << "not creating object of classid " << objectheader.getClassID() << endl;
198        mem += objectheader.getDataSize() + ( objectheader.isDiffed() ? SynchronisableHeaderLight::getSize() : SynchronisableHeader::getSize() );
199      }
200    }
201    else
202    {
203//       orxout(verbose, context::packets) << "updating object of classid " << objectheader.getClassID() << endl;
204      OrxVerify(s->updateData(mem, mode), "ERROR: could not update Synchronisable with Gamestate data");
205    }
206  }
207  assert((uintptr_t)(mem-data_) == GamestateHeader::getSize()+header_.getDataSize());
208 
209   // In debug mode, check first, whether there are no duplicate objectIDs
210#ifndef NDEBUG
211  if(this->getID()%1000==1)
212  {
213    std::list<uint32_t> v1;
214    ObjectList<Synchronisable>::iterator it;
215    for (it = ObjectList<Synchronisable>::begin(); it != ObjectList<Synchronisable>::end(); ++it)
216    {
217      if (it->getObjectID() == OBJECTID_UNKNOWN)
218      {
219        if (it->objectMode_ != 0x0)
220        {
221          orxout(user_error, context::packets) << "Found object with OBJECTID_UNKNOWN on the client with objectMode != 0x0!" << endl;
222          orxout(user_error, context::packets) << "Possible reason for this error: Client created a synchronized object without the Server's approval." << endl;
223          orxout(user_error, context::packets) << "Objects class: " << it->getIdentifier()->getName() << endl;
224          assert(false);
225        }
226      }
227      else
228      {
229        std::list<uint32_t>::iterator it2;
230        for (it2 = v1.begin(); it2 != v1.end(); ++it2)
231        {
232          if (it->getObjectID() == *it2)
233          {
234            orxout(user_error, context::packets) << "Found duplicate objectIDs on the client!" << endl
235                                                 << "Are you sure you don't create a Sychnronisable objcect with 'new' \
236                                                     that doesn't have objectMode = 0x0?" << endl;
237            assert(false);
238          }
239        }
240        v1.push_back(it->getObjectID());
241      }
242    }
243  }
244#endif
245  return true;
246}
247
248
249uint32_t Gamestate::getSize() const
250{
251  assert(data_);
252  if(header_.isCompressed())
253    return header_.getCompSize()+GamestateHeader::getSize();
254  else
255  {
256    return header_.getDataSize()+GamestateHeader::getSize();
257  }
258}
259
260
261bool Gamestate::operator==(packet::Gamestate gs)
262{
263  uint8_t *d1 = data_+GamestateHeader::getSize();
264  uint8_t *d2 = gs.data_+GamestateHeader::getSize();
265  GamestateHeader h1(data_);
266  GamestateHeader h2(gs.data_);
267  assert(h1.getDataSize() == h2.getDataSize());
268  assert(!isCompressed());
269  assert(!gs.isCompressed());
270  return memcmp(d1, d2, h1.getDataSize())==0;
271}
272
273
274bool Gamestate::process(orxonox::Host* host)
275{
276  return host->addGamestate(this, getPeerID());
277}
278
279
280bool Gamestate::compressData()
281{
282  assert(data_);
283  assert(!header_.isCompressed());
284  uLongf buffer = (uLongf)(((header_.getDataSize() + 12)*1.01)+1);
285  if(buffer==0)
286    return false;
287
288  uint8_t *ndata = new uint8_t[buffer+GamestateHeader::getSize()];
289  uint8_t *dest = ndata + GamestateHeader::getSize();
290  uint8_t *source = data_ + GamestateHeader::getSize();
291  int retval;
292  retval = compress( dest, &buffer, source, (uLong)(header_.getDataSize()) );
293  switch ( retval )
294  {
295    case Z_OK: orxout(verbose_more, context::packets) << "G.St.Man: compress: successfully compressed" << endl; break;
296    case Z_MEM_ERROR: orxout(internal_error, context::packets) << "G.St.Man: compress: not enough memory available in gamestate.compress" << endl; return false;
297    case Z_BUF_ERROR: orxout(internal_warning, context::packets) << "G.St.Man: compress: not enough memory available in the buffer in gamestate.compress" << endl; return false;
298    case Z_DATA_ERROR: orxout(internal_warning, context::packets) << "G.St.Man: compress: data corrupted in gamestate.compress" << endl; return false;
299  }
300
301  //copy and modify header
302  GamestateHeader *temp = new GamestateHeader(data_);
303  header_.setData(ndata);
304  header_ = *temp;
305  delete temp;
306  //delete old data
307  delete[] data_;
308  //save new data
309  data_ = ndata;
310  header_.setCompSize( buffer );
311  header_.setCompressed( true );
312  orxout(verbose, context::packets) << "gamestate compress datasize: " << header_.getDataSize() << " compsize: " << header_.getCompSize() << endl;
313  return true;
314}
315
316
317bool Gamestate::decompressData()
318{
319  assert(data_);
320  assert(header_.isCompressed());
321  orxout(verbose, context::packets) << "GameStateClient: uncompressing gamestate. id: " << header_.getID() << ", baseid: " << header_.getBaseID() << ", datasize: " << header_.getDataSize() << ", compsize: " << header_.getCompSize() << endl;
322  uint32_t datasize = header_.getDataSize();
323  uint32_t compsize = header_.getCompSize();
324  uint32_t bufsize;
325  bufsize = datasize;
326  assert(bufsize!=0);
327  uint8_t *ndata = new uint8_t[bufsize + GamestateHeader::getSize()];
328  uint8_t *dest = ndata + GamestateHeader::getSize();
329  uint8_t *source = data_ + GamestateHeader::getSize();
330  int retval;
331  uLongf length=bufsize;
332  retval = uncompress( dest, &length, source, (uLong)compsize );
333  switch ( retval )
334  {
335    case Z_OK: orxout(verbose_more, context::packets) << "successfully decompressed" << endl; break;
336    case Z_MEM_ERROR: orxout(internal_error, context::packets) << "not enough memory available" << endl; return false;
337    case Z_BUF_ERROR: orxout(internal_warning, context::packets) << "not enough memory available in the buffer" << endl; return false;
338    case Z_DATA_ERROR: orxout(internal_warning, context::packets) << "data corrupted (zlib)" << endl; return false;
339  }
340
341  //copy over the header
342  GamestateHeader* temp = new GamestateHeader( data_ );
343  header_.setData(ndata);
344  header_ = *temp;
345  delete temp;
346
347  if (this->bDataENetAllocated_)
348  {
349    // Memory was allocated by ENet. --> We let it be since enet_packet_destroy will
350    // deallocated it anyway. So data and packet stay together.
351    this->bDataENetAllocated_ = false;
352  }
353  else
354  {
355    // We allocated the memory in the first place (unlikely). So we destroy the old data
356    // and overwrite it with the new decompressed data.
357    delete[] this->data_;
358  }
359
360  //set new pointers
361  data_ = ndata;
362  header_.setCompressed( false );
363  assert(header_.getDataSize()==datasize);
364  assert(header_.getCompSize()==compsize);
365  return true;
366}
367
368
369inline void /*Gamestate::*/diffObject( uint8_t*& newDataPtr, uint8_t*& origDataPtr, uint8_t*& baseDataPtr, SynchronisableHeader& objectHeader, std::vector<uint32_t>::iterator& sizes )
370{
371  assert( objectHeader.getDataSize() == SynchronisableHeader(baseDataPtr).getDataSize() );
372 
373  uint32_t objectOffset = SynchronisableHeader::getSize(); // offset inside the object in the origData and baseData
374  // Check whether the whole object stayed the same
375  if( memcmp( origDataPtr+objectOffset, baseDataPtr+objectOffset, objectHeader.getDataSize()) == 0 )
376  {
377//     orxout(verbose, context::packets) << "skip object " << Synchronisable::getSynchronisable(objectHeader.getObjectID())->getIdentifier()->getName() << endl;
378    origDataPtr += objectOffset + objectHeader.getDataSize(); // skip the whole object
379    baseDataPtr += objectOffset + objectHeader.getDataSize();
380    sizes += Synchronisable::getSynchronisable(objectHeader.getObjectID())->getNrOfVariables();
381  }
382  else
383  {
384    // Now start to diff the Object
385    SynchronisableHeaderLight newObjectHeader(newDataPtr);
386    newObjectHeader = objectHeader; // copy over the objectheader
387    VariableID variableID = 0;
388    uint32_t diffedObjectOffset = SynchronisableHeaderLight::getSize();
389    // iterate through all variables
390    while( objectOffset < objectHeader.getDataSize()+SynchronisableHeader::getSize() )
391    {
392      // check whether variable changed and write id and copy over variable to the new stream
393      // otherwise skip variable
394      uint32_t varSize = *sizes;
395      assert( varSize == Synchronisable::getSynchronisable(objectHeader.getObjectID())->getVarSize(variableID) );
396      if ( varSize != 0 )
397      {
398        if ( memcmp(origDataPtr+objectOffset, baseDataPtr+objectOffset, varSize) != 0 )
399        {
400          *(VariableID*)(newDataPtr+diffedObjectOffset) = variableID; // copy over the variableID
401          diffedObjectOffset += sizeof(VariableID);
402          memcpy( newDataPtr+diffedObjectOffset, origDataPtr+objectOffset, varSize );
403          diffedObjectOffset += varSize;
404          objectOffset += varSize;
405        }
406        else
407        {
408          objectOffset += varSize;
409        }
410      }
411
412      ++variableID;
413      ++sizes;
414    }
415   
416    // if there are variables from this object with 0 size left in sizes
417    if( Synchronisable::getSynchronisable(objectHeader.getObjectID())->getNrOfVariables() != variableID )
418      sizes += Synchronisable::getSynchronisable(objectHeader.getObjectID())->getNrOfVariables() - variableID;
419   
420    newObjectHeader.setDiffed(true);
421    newObjectHeader.setDataSize(diffedObjectOffset-SynchronisableHeaderLight::getSize());
422    assert(objectOffset == objectHeader.getDataSize()+SynchronisableHeader::getSize());
423    assert(newObjectHeader.getDataSize()>0);
424   
425    origDataPtr += objectOffset;
426    baseDataPtr += objectOffset;
427    newDataPtr += diffedObjectOffset;
428  }
429}
430
431inline void /*Gamestate::*/copyObject( uint8_t*& newData, uint8_t*& origData, uint8_t*& baseData, SynchronisableHeader& objectHeader, std::vector<uint32_t>::iterator& sizes )
432{
433  //       orxout(verbose, context::packets) << "docopy" << endl;
434  // Just copy over the whole Object
435  memcpy( newData, origData, objectHeader.getDataSize()+SynchronisableHeader::getSize() );
436  SynchronisableHeader(newData).setDiffed(false);
437 
438  newData += objectHeader.getDataSize()+SynchronisableHeader::getSize();
439  origData += objectHeader.getDataSize()+SynchronisableHeader::getSize();
440//   SynchronisableHeader baseHeader( baseData );
441//   baseData += baseHeader.getDataSize()+SynchronisableHeader::getSize();
442  //       orxout(verbose, context::packets) << "copy " << h.getObjectID() << endl;
443  //       orxout(verbose, context::packets) << "copy " << h.getObjectID() << ":";
444  sizes += Synchronisable::getSynchronisable(objectHeader.getObjectID())->getNrOfVariables();
445//   for( unsigned int i = 0; i < Synchronisable::getSynchronisable(objectHeader.getObjectID())->getNrOfVariables(); ++i )
446//   {
447//     //         orxout(verbose, context::packets) << " " << *sizes;
448//     ++sizes;
449//   }
450    //       orxout(verbose, context::packets) << endl;
451}
452
453inline bool findObject(uint8_t*& dataPtr, uint8_t* endPtr, SynchronisableHeader& objectHeader)
454{
455  // Some assertions to make sure the dataPtr is valid (pointing to a SynchronisableHeader)
456  {
457    SynchronisableHeader htemp2(dataPtr);
458    assert(htemp2.getClassID()<500);
459    assert(htemp2.getDataSize()!=0 && htemp2.getDataSize()<1000);
460    assert(htemp2.isDiffed()==false);
461  }
462  uint32_t objectID = objectHeader.getObjectID();
463  while ( dataPtr < endPtr )
464  {
465    SynchronisableHeader htemp(dataPtr);
466    assert( htemp.getDataSize()!=0 );
467    if ( htemp.getObjectID() == objectID )
468    {
469      assert( objectHeader.getClassID() == htemp.getClassID() );
470      assert( objectHeader.getCreatorID() == htemp.getCreatorID() );
471      return true;
472    }
473    {
474      if( dataPtr+htemp.getDataSize()+SynchronisableHeader::getSize() < endPtr )
475      {
476        SynchronisableHeader htemp2(dataPtr+htemp.getDataSize()+SynchronisableHeader::getSize());
477        assert(htemp2.getClassID()<500);
478        assert(htemp2.getDataSize()!=0 && htemp2.getDataSize()<1000);
479        assert(htemp2.isDiffed()==false);
480      }
481    }
482    dataPtr += htemp.getDataSize()+SynchronisableHeader::getSize();
483   
484  }
485  assert(dataPtr == endPtr);
486 
487  return false;
488}
489
490Gamestate* Gamestate::diffVariables(Gamestate *base)
491{
492  assert(this && base); assert(data_ && base->data_);
493  assert(!header_.isCompressed() && !base->header_.isCompressed());
494  assert(!header_.isDiffed());
495  assert( header_.getDataSize() && base->header_.getDataSize() );
496
497
498  // *** first do a raw diff of the two gamestates
499
500  uint8_t *baseDataPtr = GAMESTATE_START(base->data_);
501  uint8_t *origDataPtr = GAMESTATE_START(this->data_);
502  uint8_t *origDataEnd = origDataPtr + header_.getDataSize();
503  uint8_t *baseDataEnd = baseDataPtr + base->header_.getDataSize();
504//   uint32_t origLength = header_.getDataSize();
505//   uint32_t baseLength = base->header_.getDataSize();
506
507  // Allocate new space for diffed gamestate
508  uint32_t newDataSize = header_.getDataSize() + GamestateHeader::getSize() + sizeof(uint32_t)*this->nrOfVariables_;
509  uint8_t *newData = new uint8_t[newDataSize]; // this is the maximum size needed in the worst case
510  uint8_t *destDataPtr = GAMESTATE_START(newData);
511
512  std::vector<uint32_t>::iterator sizesIt = this->sizes_.begin();
513
514  while( origDataPtr < origDataEnd )
515  {
516    //iterate through all objects
517
518    SynchronisableHeader origHeader(origDataPtr);
519
520    // Find (if possible) the current object in the datastream of the old gamestate
521    // Start at the current offset position
522    if(baseDataPtr == baseDataEnd)
523      baseDataPtr = GAMESTATE_START(base->data_);
524    uint8_t* oldBaseDataPtr = baseDataPtr;
525   
526    assert(baseDataPtr < baseDataEnd);
527    assert(destDataPtr < newData + newDataSize);
528    assert(sizesIt != this->sizes_.end());
529   
530    assert(Synchronisable::getSynchronisable(origHeader.getObjectID()));
531    assert(ClassByID(origHeader.getClassID()));
532    assert(origHeader.getDataSize() < 500);
533   
534    bool diffedObject = false;
535    if( findObject(baseDataPtr, baseDataEnd, origHeader) )
536    {
537      SynchronisableHeader baseHeader(baseDataPtr);
538      assert(Synchronisable::getSynchronisable(baseHeader.getObjectID()));
539      assert(ClassByID(baseHeader.getClassID()));
540      assert(baseHeader.getDataSize() < 500);
541      if( SynchronisableHeader(baseDataPtr).getDataSize()==origHeader.getDataSize() )
542      {
543//         orxout(verbose, context::packets) << "diffing object in order: " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
544        diffObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
545        diffedObject = true;
546      }
547      else
548      {
549//         orxout(verbose, context::packets) << "copy object because of different data sizes (1): " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
550        copyObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
551        assert(sizesIt != this->sizes_.end() || origDataPtr==origDataEnd);
552      }
553       
554    }
555    else
556    {
557      assert( baseDataPtr == baseDataEnd );
558      baseDataPtr = GAMESTATE_START(base->data_);
559      if( findObject(baseDataPtr, oldBaseDataPtr, origHeader) )
560      {
561        SynchronisableHeader baseHeader(baseDataPtr);
562        assert(Synchronisable::getSynchronisable(baseHeader.getObjectID()));
563        assert(ClassByID(baseHeader.getClassID()));
564        assert(baseHeader.getDataSize() < 500);
565        if( SynchronisableHeader(baseDataPtr).getDataSize()==origHeader.getDataSize() )
566        {
567//           orxout(verbose, context::packets) << "diffing object out of order: " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
568          diffObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
569          diffedObject = true;
570        }
571        else
572        {
573//           orxout(verbose, context::packets) << "copy object because of different data sizes (2): " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
574          copyObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
575          assert(sizesIt != this->sizes_.end() || origDataPtr==origDataEnd);
576        }
577      }
578      else
579      {
580//         orxout(verbose, context::packets) << "copy object: " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
581        assert(baseDataPtr == oldBaseDataPtr);
582        copyObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
583        assert(sizesIt != this->sizes_.end() || origDataPtr==origDataEnd);
584      }
585    }
586  }
587  assert(sizesIt==this->sizes_.end());
588
589
590  Gamestate *g = new Gamestate(newData, getPeerID());
591  (g->header_) = header_;
592  g->header_.setBaseID( base->getID() );
593  g->header_.setDataSize(destDataPtr - newData - GamestateHeader::getSize());
594  g->flags_=flags_;
595  g->packetDirection_ = packetDirection_;
596  assert(!g->isCompressed());
597  return g;
598}
599
600
601/*Gamestate* Gamestate::diffData(Gamestate *base)
602{
603  assert(this && base); assert(data_ && base->data_);
604  assert(!header_.isCompressed() && !base->header_.isCompressed());
605  assert(!header_.isDiffed());
606
607  uint8_t *basep = GAMESTATE_START(base->data_);
608  uint8_t *gs = GAMESTATE_START(this->data_);
609  uint32_t dest_length = header_.getDataSize();
610
611  if(dest_length==0)
612    return NULL;
613
614  uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
615  uint8_t *dest = GAMESTATE_START(ndata);
616
617  rawDiff( dest, gs, basep, header_.getDataSize(), base->header_.getDataSize() );
618#ifndef NDEBUG
619  uint8_t *dest2 = new uint8_t[dest_length];
620  rawDiff( dest2, dest, basep, header_.getDataSize(), base->header_.getDataSize() );
621  assert( memcmp( dest2, gs, dest_length) == 0 );
622  delete dest2;
623#endif
624
625  Gamestate *g = new Gamestate(ndata, getClientID());
626  assert(g->header_);
627  *(g->header_) = *header_;
628  g->header_.setDiffed( true );
629  g->header_.setBaseID( base->getID() );
630  g->flags_=flags_;
631  g->packetDirection_ = packetDirection_;
632  assert(g->isDiffed());
633  assert(!g->isCompressed());
634  return g;
635}
636
637
638Gamestate* Gamestate::undiff(Gamestate *base)
639{
640  assert(this && base); assert(data_ && base->data_);
641  assert(!header_.isCompressed() && !base->header_.isCompressed());
642  assert(header_.isDiffed());
643
644  uint8_t *basep = GAMESTATE_START(base->data_);
645  uint8_t *gs = GAMESTATE_START(this->data_);
646  uint32_t dest_length = header_.getDataSize();
647
648  if(dest_length==0)
649    return NULL;
650
651  uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
652  uint8_t *dest = ndata + GamestateHeader::getSize();
653
654  rawDiff( dest, gs, basep, header_.getDataSize(), base->header_.getDataSize() );
655
656  Gamestate *g = new Gamestate(ndata, getClientID());
657  assert(g->header_);
658  *(g->header_) = *header_;
659  g->header_.setDiffed( false );
660  g->flags_=flags_;
661  g->packetDirection_ = packetDirection_;
662  assert(!g->isDiffed());
663  assert(!g->isCompressed());
664  return g;
665}
666
667
668void Gamestate::rawDiff( uint8_t* newdata, uint8_t* data, uint8_t* basedata, uint32_t datalength, uint32_t baselength)
669{
670  uint64_t* gd = (uint64_t*)data;
671  uint64_t* bd = (uint64_t*)basedata;
672  uint64_t* nd = (uint64_t*)newdata;
673
674  unsigned int i;
675  for( i=0; i<datalength/8; i++ )
676  {
677    if( i<baselength/8 )
678      *(nd+i) = *(gd+i) ^ *(bd+i);  // xor the data
679    else
680      *(nd+i) = *(gd+i); // just copy over the data
681  }
682  unsigned int j;
683  // now process the rest (when datalength isn't a multiple of 4)
684  for( j = 8*(datalength/8); j<datalength; j++ )
685  {
686    if( j<baselength )
687      *(newdata+j) = *(data+j) ^ *(basedata+j); // xor
688    else
689      *(newdata+j) = *(data+j); // just copy
690  }
691  assert(j==datalength);
692}*/
693
694
695/*Gamestate* Gamestate::doSelection(unsigned int clientID, unsigned int targetSize){
696  assert(data_);
697  std::list<obj>::iterator it;
698
699  // allocate memory for new data
700  uint8_t *gdata = new uint8_t[header_.getDataSize()+GamestateHeader::getSize()];
701  // create a gamestate out of it
702  Gamestate *gs = new Gamestate(gdata);
703  uint8_t *newdata = gdata + GamestateHeader::getSize();
704  uint8_t *origdata = GAMESTATE_START(data_);
705
706  //copy the GamestateHeader
707  assert(gs->header_);
708  *(gs->header_) = *header_;
709
710  uint32_t objectOffset;
711  unsigned int objectsize, destsize=0;
712  // TODO: Why is this variable not used?
713  //Synchronisable *object;
714
715  //call TrafficControl
716  TrafficControl::getInstance()->processObjectList( clientID, header_.getID(), dataVector_ );
717
718  //copy in the zeros
719//   std::list<obj>::iterator itt;
720//   orxout() << "myvector contains:";
721//   for ( itt=dataVector_.begin() ; itt!=dataVector_.end(); itt++ )
722//     orxout() << " " << (*itt).objID;
723//   orxout() << endl;
724  for(it=dataVector_.begin(); it!=dataVector_.end();){
725    SynchronisableHeader oldobjectheader(origdata);
726    SynchronisableHeader newobjectheader(newdata);
727    if ( (*it).objSize == 0 )
728    {
729      ++it;
730      continue;
731    }
732    objectsize = oldobjectheader.getDataSize()+SynchronisableHeader::getSize();
733    objectOffset=SynchronisableHeader::getSize(); //skip the size and the availableData variables in the objectheader
734    if ( (*it).objID == oldobjectheader.getObjectID() ){
735      memcpy(newdata, origdata, objectsize);
736      ++it;
737    }else{
738      newobjectheader = oldobjectheader;
739      memset(newdata+objectOffset, 0, objectsize-objectOffset);
740    }
741    newdata += objectsize;
742    origdata += objectsize;
743    destsize += objectsize;
744  }
745#ifndef NDEBUG
746  uint32_t origsize = destsize;
747  while ( origsize < header_.getDataSize() )
748  {
749    SynchronisableHeader oldobjectheader(origdata);
750    objectsize = oldobjectheader.getDataSize()+SynchronisableHeader::getSize();
751    origdata += objectsize;
752    origsize += objectsize;
753  }
754  assert(origsize==header_.getDataSize());
755  assert(destsize!=0);
756#endif
757  gs->header_.setDataSize( destsize );
758  return gs;
759}*/
760
761
762uint32_t Gamestate::calcGamestateSize(uint32_t id, uint8_t mode)
763{
764  uint32_t size = 0;
765  uint32_t nrOfVariables = 0;
766    // get the start of the Synchronisable list
767  ObjectList<Synchronisable>::iterator it;
768    // get total size of gamestate
769  for(it = ObjectList<Synchronisable>::begin(); it; ++it){
770    size+=it->getSize(id, mode); // size of the actual data of the synchronisable
771    nrOfVariables += it->getNrOfVariables();
772  }
773//   orxout() << "allocating " << nrOfVariables << " ints" << endl;
774  this->sizes_.reserve(nrOfVariables);
775  return size;
776}
777
778
779} //namespace packet
780} //namespace orxonox
Note: See TracBrowser for help on using the repository browser.