Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/network/packet/Gamestate.cc @ 9017

Last change on this file since 9017 was 8952, checked in by dafrick, 13 years ago

Removing some unused variables and taking care of some other warnings (NULL as argument to non-pointer and depricated use of COUT).

  • Property svn:eol-style set to native
File size: 26.8 KB
RevLine 
[1711]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:
[3084]23 *      Oliver Scheuss
[1711]24 *   Co-authors:
25 *      ...
26 *
27 */
28
[1701]29#include "Gamestate.h"
[3214]30
[2773]31#include <zlib.h>
[3214]32
[8858]33#include "util/Output.h"
[8373]34#include "util/OrxAssert.h"
[2896]35#include "core/GameMode.h"
[3214]36#include "core/ObjectList.h"
37#include "network/synchronisable/Synchronisable.h"
38#include "network/GamestateHandler.h"
[7801]39#include "network/Host.h"
[1701]40
[2171]41namespace orxonox {
[1701]42
43namespace packet {
44
[2662]45#define GAMESTATE_START(data) (data + GamestateHeader::getSize())
[1740]46
[7801]47// #define PACKET_FLAG_GAMESTATE  PacketFlag::Reliable
48#define PACKET_FLAG_GAMESTATE  0
[2087]49
[7163]50inline bool memzero( uint8_t* data, uint32_t datalength)
51{
52  uint64_t* d = (uint64_t*)data;
[2662]53
[7163]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():
[7801]70  header_()
[1701]71{
[1907]72  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
[1701]73}
74
[7163]75
[1907]76Gamestate::Gamestate(uint8_t *data, unsigned int clientID):
[7801]77  Packet(data, clientID), header_(data)
[1701]78{
[1907]79  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
[1701]80}
81
[7163]82
[7801]83Gamestate::Gamestate(uint8_t *data):
84  header_(data)
[1907]85{
86  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
[7163]87  data_ = data;
[1907]88}
[1701]89
[7163]90
[2662]91Gamestate::Gamestate(const Gamestate& g) :
[7801]92  Packet( *(Packet*)&g ), header_(this->data_), nrOfVariables_(0)
[2662]93{
94  flags_ = flags_ | PACKET_FLAG_GAMESTATE;
[7163]95  sizes_ = g.sizes_;
[2662]96}
[1907]97
[2662]98
[1701]99Gamestate::~Gamestate()
100{
101}
102
[7163]103
[2171]104bool Gamestate::collectData(int id, uint8_t mode)
[1701]105{
[2662]106  uint32_t tempsize=0, currentsize=0;
[1751]107  assert(data_==0);
[2662]108  uint32_t size = calcGamestateSize(id, mode);
[1740]109
[8858]110  orxout(verbose_more, context::packets) << "G.ST.Man: producing gamestate with id: " << id << endl;
[1701]111  if(size==0)
112    return false;
[2662]113  data_ = new uint8_t[size + GamestateHeader::getSize()];
[7163]114  if(!data_)
115  {
[8858]116    orxout(internal_warning, context::packets) << "GameStateManager: could not allocate memory" << endl;
[1701]117    return false;
118  }
[6417]119
[7801]120  // tell the gamestate header where to store the data
121  header_.setData(this->data_);
[2087]122
[1701]123  //start collect data synchronisable by synchronisable
[7163]124  uint8_t *mem = data_; // in this stream store all data of the variables and the headers of the synchronisable
[2662]125  mem += GamestateHeader::getSize();
[2171]126  ObjectList<Synchronisable>::iterator it;
[7163]127  for(it = ObjectList<Synchronisable>::begin(); it; ++it)
128  {
[6417]129
[3084]130//     tempsize=it->getSize(id, mode);
131
[7163]132    tempsize = it->getData(mem, this->sizes_, id, mode);
[3084]133    if ( tempsize != 0 )
134      dataVector_.push_back( obj(it->getObjectID(), it->getCreatorID(), tempsize, mem-data_) );
[6417]135
[2662]136#ifndef NDEBUG
[7163]137    if(currentsize+tempsize > size)
138    {
[2171]139      assert(0); // if we don't use multithreading this part shouldn't be neccessary
[1701]140      // start allocate additional memory
[8858]141      orxout(internal_info, context::packets) << "Gamestate: need additional memory" << endl;
[2171]142      ObjectList<Synchronisable>::iterator temp = it;
[2662]143      uint32_t addsize=tempsize;
[1701]144      while(++temp)
[1907]145        addsize+=temp->getSize(id, mode);
[2662]146      data_ = (uint8_t *)realloc(data_, GamestateHeader::getSize() + currentsize + addsize);
[1701]147      if(!data_)
148        return false;
149      size = currentsize+addsize;
150    }// stop allocate additional memory
[2662]151#endif
[3084]152//     if(!it->getData(mem, id, mode))
153//       return false; // mem pointer gets automatically increased because of call by reference
[1701]154    // increase size counter by size of current synchronisable
155    currentsize+=tempsize;
156  }
[1740]157
158
[1701]159  //start write gamestate header
[7801]160  header_.setDataSize( currentsize );
[8327]161  header_.setCompSize( 0 );
[7801]162  header_.setID( id );
163  header_.setBaseID( GAMESTATEID_INITIAL );
164  header_.setDiffed( false );
165  header_.setComplete( true );
166  header_.setCompressed( false );
[1701]167  //stop write gamestate header
[1740]168
[8858]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;
[1701]171  return true;
172}
173
[7163]174
[2171]175bool Gamestate::spreadData(uint8_t mode)
[1701]176{
[8858]177  orxout(verbose_more, context::packets) << "processing gamestate with id " << header_.getID() << endl;
[1751]178  assert(data_);
[7801]179  assert(!header_.isCompressed());
[2662]180  uint8_t *mem=data_+GamestateHeader::getSize();
[1907]181  Synchronisable *s;
[7801]182 
[1907]183  // update the data of the objects we received
[7801]184  while(mem < data_+GamestateHeader::getSize()+header_.getDataSize())
[7163]185  {
[2662]186    SynchronisableHeader objectheader(mem);
[1701]187
[2662]188    s = Synchronisable::getSynchronisable( objectheader.getObjectID() );
[1907]189    if(!s)
[1701]190    {
[2896]191      if (!GameMode::isMaster())
[2662]192      {
193        Synchronisable::fabricate(mem, mode);
194      }
195      else
196      {
[8858]197//         orxout(verbose, context::packets) << "not creating object of classid " << objectheader.getClassID() << endl;
[7163]198        mem += objectheader.getDataSize() + ( objectheader.isDiffed() ? SynchronisableHeaderLight::getSize() : SynchronisableHeader::getSize() );
[2662]199      }
[1701]200    }
[1907]201    else
202    {
[8858]203//       orxout(verbose, context::packets) << "updating object of classid " << objectheader.getClassID() << endl;
[8394]204      OrxVerify(s->updateData(mem, mode), "ERROR: could not update Synchronisable with Gamestate data");
[1907]205    }
[1701]206  }
[7844]207  assert((uintptr_t)(mem-data_) == GamestateHeader::getSize()+header_.getDataSize());
[7801]208 
[2662]209   // In debug mode, check first, whether there are no duplicate objectIDs
210#ifndef NDEBUG
[7163]211  if(this->getID()%1000==1)
212  {
[3084]213    std::list<uint32_t> v1;
214    ObjectList<Synchronisable>::iterator it;
[7163]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        {
[8858]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;
[3084]224          assert(false);
225        }
[2662]226      }
[7163]227      else
228      {
[3084]229        std::list<uint32_t>::iterator it2;
[7163]230        for (it2 = v1.begin(); it2 != v1.end(); ++it2)
231        {
232          if (it->getObjectID() == *it2)
233          {
[8858]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;
[3084]237            assert(false);
238          }
[2662]239        }
[3084]240        v1.push_back(it->getObjectID());
[2662]241      }
242    }
243  }
244#endif
[1701]245  return true;
246}
247
[7163]248
[2662]249uint32_t Gamestate::getSize() const
[1701]250{
[1711]251  assert(data_);
[7801]252  if(header_.isCompressed())
253    return header_.getCompSize()+GamestateHeader::getSize();
[1701]254  else
255  {
[7801]256    return header_.getDataSize()+GamestateHeader::getSize();
[1701]257  }
258}
259
[7163]260
261bool Gamestate::operator==(packet::Gamestate gs)
262{
[2662]263  uint8_t *d1 = data_+GamestateHeader::getSize();
264  uint8_t *d2 = gs.data_+GamestateHeader::getSize();
[8394]265  GamestateHeader h1(data_);
266  GamestateHeader h2(gs.data_);
267  assert(h1.getDataSize() == h2.getDataSize());
[1751]268  assert(!isCompressed());
269  assert(!gs.isCompressed());
[8394]270  return memcmp(d1, d2, h1.getDataSize())==0;
[1751]271}
272
[7163]273
[7801]274bool Gamestate::process(orxonox::Host* host)
[1701]275{
[7801]276  return host->addGamestate(this, getPeerID());
[1701]277}
278
[1907]279
[1701]280bool Gamestate::compressData()
281{
[2662]282  assert(data_);
[7801]283  assert(!header_.isCompressed());
284  uLongf buffer = (uLongf)(((header_.getDataSize() + 12)*1.01)+1);
[1701]285  if(buffer==0)
286    return false;
[1740]287
[2662]288  uint8_t *ndata = new uint8_t[buffer+GamestateHeader::getSize()];
289  uint8_t *dest = ndata + GamestateHeader::getSize();
290  uint8_t *source = data_ + GamestateHeader::getSize();
[1701]291  int retval;
[7801]292  retval = compress( dest, &buffer, source, (uLong)(header_.getDataSize()) );
[7163]293  switch ( retval )
294  {
[8858]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;
[1701]299  }
300
301  //copy and modify header
[7801]302  GamestateHeader *temp = new GamestateHeader(data_);
303  header_.setData(ndata);
304  header_ = *temp;
[2662]305  delete temp;
[1701]306  //delete old data
307  delete[] data_;
308  //save new data
309  data_ = ndata;
[7801]310  header_.setCompSize( buffer );
311  header_.setCompressed( true );
[8858]312  orxout(verbose, context::packets) << "gamestate compress datasize: " << header_.getDataSize() << " compsize: " << header_.getCompSize() << endl;
[1701]313  return true;
314}
[7163]315
316
[1701]317bool Gamestate::decompressData()
318{
[2662]319  assert(data_);
[7801]320  assert(header_.isCompressed());
[8858]321  orxout(verbose, context::packets) << "GameStateClient: uncompressing gamestate. id: " << header_.getID() << ", baseid: " << header_.getBaseID() << ", datasize: " << header_.getDataSize() << ", compsize: " << header_.getCompSize() << endl;
[7801]322  uint32_t datasize = header_.getDataSize();
323  uint32_t compsize = header_.getCompSize();
[2662]324  uint32_t bufsize;
[1907]325  bufsize = datasize;
[1751]326  assert(bufsize!=0);
[2662]327  uint8_t *ndata = new uint8_t[bufsize + GamestateHeader::getSize()];
328  uint8_t *dest = ndata + GamestateHeader::getSize();
329  uint8_t *source = data_ + GamestateHeader::getSize();
[1701]330  int retval;
[1751]331  uLongf length=bufsize;
332  retval = uncompress( dest, &length, source, (uLong)compsize );
[7163]333  switch ( retval )
334  {
[8858]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;
[1701]339  }
[1752]340
[1701]341  //copy over the header
[7801]342  GamestateHeader* temp = new GamestateHeader( data_ );
343  header_.setData(ndata);
344  header_ = *temp;
[2662]345  delete temp;
[2087]346
[7163]347  if (this->bDataENetAllocated_)
348  {
[2087]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  }
[7163]353  else
354  {
[2087]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
[1751]360  //set new pointers
[1701]361  data_ = ndata;
[7801]362  header_.setCompressed( false );
363  assert(header_.getDataSize()==datasize);
364  assert(header_.getCompSize()==compsize);
[1701]365  return true;
366}
367
[7163]368
[7801]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  {
[8858]377//     orxout(verbose, context::packets) << "skip object " << Synchronisable::getSynchronisable(objectHeader.getObjectID())->getIdentifier()->getName() << endl;
[7801]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{
[8858]433  //       orxout(verbose, context::packets) << "docopy" << endl;
[7801]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();
[8858]442  //       orxout(verbose, context::packets) << "copy " << h.getObjectID() << endl;
443  //       orxout(verbose, context::packets) << "copy " << h.getObjectID() << ":";
[7801]444  sizes += Synchronisable::getSynchronisable(objectHeader.getObjectID())->getNrOfVariables();
445//   for( unsigned int i = 0; i < Synchronisable::getSynchronisable(objectHeader.getObjectID())->getNrOfVariables(); ++i )
446//   {
[8858]447//     //         orxout(verbose, context::packets) << " " << *sizes;
[7801]448//     ++sizes;
449//   }
[8858]450    //       orxout(verbose, context::packets) << endl;
[7801]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
[7163]490Gamestate* Gamestate::diffVariables(Gamestate *base)
[1701]491{
[7163]492  assert(this && base); assert(data_ && base->data_);
[7801]493  assert(!header_.isCompressed() && !base->header_.isCompressed());
494  assert(!header_.isDiffed());
495  assert( header_.getDataSize() && base->header_.getDataSize() );
[7163]496
497
498  // *** first do a raw diff of the two gamestates
499
[7801]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();
[7163]506
[7801]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);
[7163]511
[7801]512  std::vector<uint32_t>::iterator sizesIt = this->sizes_.begin();
[7163]513
[7801]514  while( origDataPtr < origDataEnd )
[7163]515  {
516    //iterate through all objects
517
[7801]518    SynchronisableHeader origHeader(origDataPtr);
[7163]519
520    // Find (if possible) the current object in the datastream of the old gamestate
521    // Start at the current offset position
[7801]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    if( findObject(baseDataPtr, baseDataEnd, origHeader) )
[7163]535    {
[7801]536      SynchronisableHeader baseHeader(baseDataPtr);
537      assert(Synchronisable::getSynchronisable(baseHeader.getObjectID()));
538      assert(ClassByID(baseHeader.getClassID()));
539      assert(baseHeader.getDataSize() < 500);
540      if( SynchronisableHeader(baseDataPtr).getDataSize()==origHeader.getDataSize() )
[7163]541      {
[8858]542//         orxout(verbose, context::packets) << "diffing object in order: " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
[7801]543        diffObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
[1701]544      }
[7801]545      else
[7163]546      {
[8858]547//         orxout(verbose, context::packets) << "copy object because of different data sizes (1): " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
[7801]548        copyObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
549        assert(sizesIt != this->sizes_.end() || origDataPtr==origDataEnd);
[7163]550      }
[7801]551       
[7163]552    }
[7801]553    else
[7163]554    {
[7801]555      assert( baseDataPtr == baseDataEnd );
556      baseDataPtr = GAMESTATE_START(base->data_);
557      if( findObject(baseDataPtr, oldBaseDataPtr, origHeader) )
[7163]558      {
[7801]559        SynchronisableHeader baseHeader(baseDataPtr);
560        assert(Synchronisable::getSynchronisable(baseHeader.getObjectID()));
561        assert(ClassByID(baseHeader.getClassID()));
562        assert(baseHeader.getDataSize() < 500);
563        if( SynchronisableHeader(baseDataPtr).getDataSize()==origHeader.getDataSize() )
[7163]564        {
[8858]565//           orxout(verbose, context::packets) << "diffing object out of order: " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
[7801]566          diffObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
[7163]567        }
[7801]568        else
569        {
[8858]570//           orxout(verbose, context::packets) << "copy object because of different data sizes (2): " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
[7801]571          copyObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
572          assert(sizesIt != this->sizes_.end() || origDataPtr==origDataEnd);
573        }
[7163]574      }
[7801]575      else
[7163]576      {
[8858]577//         orxout(verbose, context::packets) << "copy object: " << Synchronisable::getSynchronisable(origHeader.getObjectID())->getIdentifier()->getName() << endl;
[7801]578        assert(baseDataPtr == oldBaseDataPtr);
579        copyObject(destDataPtr, origDataPtr, baseDataPtr, origHeader, sizesIt);
580        assert(sizesIt != this->sizes_.end() || origDataPtr==origDataEnd);
[7163]581      }
582    }
[1701]583  }
[7801]584  assert(sizesIt==this->sizes_.end());
[1701]585
[7163]586
[7801]587  Gamestate *g = new Gamestate(newData, getPeerID());
588  (g->header_) = header_;
589  g->header_.setBaseID( base->getID() );
590  g->header_.setDataSize(destDataPtr - newData - GamestateHeader::getSize());
[1751]591  g->flags_=flags_;
592  g->packetDirection_ = packetDirection_;
[7163]593  assert(!g->isCompressed());
[1701]594  return g;
[7163]595}
[3198]596
[7163]597
[7801]598/*Gamestate* Gamestate::diffData(Gamestate *base)
[3198]599{
600  assert(this && base); assert(data_ && base->data_);
[7801]601  assert(!header_.isCompressed() && !base->header_.isCompressed());
602  assert(!header_.isDiffed());
[6417]603
[3198]604  uint8_t *basep = GAMESTATE_START(base->data_);
605  uint8_t *gs = GAMESTATE_START(this->data_);
[7801]606  uint32_t dest_length = header_.getDataSize();
[6417]607
[3198]608  if(dest_length==0)
609    return NULL;
[6417]610
[3198]611  uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
612  uint8_t *dest = GAMESTATE_START(ndata);
[6417]613
[7801]614  rawDiff( dest, gs, basep, header_.getDataSize(), base->header_.getDataSize() );
[3198]615#ifndef NDEBUG
616  uint8_t *dest2 = new uint8_t[dest_length];
[7801]617  rawDiff( dest2, dest, basep, header_.getDataSize(), base->header_.getDataSize() );
[3198]618  assert( memcmp( dest2, gs, dest_length) == 0 );
[5929]619  delete dest2;
[3198]620#endif
621
622  Gamestate *g = new Gamestate(ndata, getClientID());
623  assert(g->header_);
624  *(g->header_) = *header_;
[7801]625  g->header_.setDiffed( true );
626  g->header_.setBaseID( base->getID() );
[3198]627  g->flags_=flags_;
628  g->packetDirection_ = packetDirection_;
629  assert(g->isDiffed());
630  assert(!g->isCompressed());
631  return g;
[1701]632}
633
[7163]634
635Gamestate* Gamestate::undiff(Gamestate *base)
[3198]636{
637  assert(this && base); assert(data_ && base->data_);
[7801]638  assert(!header_.isCompressed() && !base->header_.isCompressed());
639  assert(header_.isDiffed());
[6417]640
[3198]641  uint8_t *basep = GAMESTATE_START(base->data_);
642  uint8_t *gs = GAMESTATE_START(this->data_);
[7801]643  uint32_t dest_length = header_.getDataSize();
[6417]644
[3198]645  if(dest_length==0)
646    return NULL;
[6417]647
[3198]648  uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
649  uint8_t *dest = ndata + GamestateHeader::getSize();
[6417]650
[7801]651  rawDiff( dest, gs, basep, header_.getDataSize(), base->header_.getDataSize() );
[6417]652
[3198]653  Gamestate *g = new Gamestate(ndata, getClientID());
654  assert(g->header_);
655  *(g->header_) = *header_;
[7801]656  g->header_.setDiffed( false );
[3198]657  g->flags_=flags_;
658  g->packetDirection_ = packetDirection_;
659  assert(!g->isDiffed());
660  assert(!g->isCompressed());
661  return g;
662}
663
664
665void Gamestate::rawDiff( uint8_t* newdata, uint8_t* data, uint8_t* basedata, uint32_t datalength, uint32_t baselength)
666{
667  uint64_t* gd = (uint64_t*)data;
668  uint64_t* bd = (uint64_t*)basedata;
669  uint64_t* nd = (uint64_t*)newdata;
[6417]670
[3198]671  unsigned int i;
672  for( i=0; i<datalength/8; i++ )
673  {
674    if( i<baselength/8 )
675      *(nd+i) = *(gd+i) ^ *(bd+i);  // xor the data
676    else
677      *(nd+i) = *(gd+i); // just copy over the data
678  }
679  unsigned int j;
680  // now process the rest (when datalength isn't a multiple of 4)
681  for( j = 8*(datalength/8); j<datalength; j++ )
682  {
683    if( j<baselength )
684      *(newdata+j) = *(data+j) ^ *(basedata+j); // xor
685    else
686      *(newdata+j) = *(data+j); // just copy
687  }
688  assert(j==datalength);
[7801]689}*/
[3198]690
[7163]691
[7801]692/*Gamestate* Gamestate::doSelection(unsigned int clientID, unsigned int targetSize){
[1907]693  assert(data_);
[2662]694  std::list<obj>::iterator it;
[2087]695
[1907]696  // allocate memory for new data
[7801]697  uint8_t *gdata = new uint8_t[header_.getDataSize()+GamestateHeader::getSize()];
[1907]698  // create a gamestate out of it
699  Gamestate *gs = new Gamestate(gdata);
[2662]700  uint8_t *newdata = gdata + GamestateHeader::getSize();
[1907]701  uint8_t *origdata = GAMESTATE_START(data_);
[2087]702
[1907]703  //copy the GamestateHeader
[2662]704  assert(gs->header_);
705  *(gs->header_) = *header_;
[2087]706
[2662]707  uint32_t objectOffset;
708  unsigned int objectsize, destsize=0;
709  // TODO: Why is this variable not used?
710  //Synchronisable *object;
[2087]711
[2662]712  //call TrafficControl
[7801]713  TrafficControl::getInstance()->processObjectList( clientID, header_.getID(), dataVector_ );
[2662]714
[1907]715  //copy in the zeros
[3084]716//   std::list<obj>::iterator itt;
[8858]717//   orxout() << "myvector contains:";
[3084]718//   for ( itt=dataVector_.begin() ; itt!=dataVector_.end(); itt++ )
[8858]719//     orxout() << " " << (*itt).objID;
720//   orxout() << endl;
[3084]721  for(it=dataVector_.begin(); it!=dataVector_.end();){
[2662]722    SynchronisableHeader oldobjectheader(origdata);
723    SynchronisableHeader newobjectheader(newdata);
[7163]724    if ( (*it).objSize == 0 )
[2662]725    {
726      ++it;
727      continue;
728    }
[7163]729    objectsize = oldobjectheader.getDataSize()+SynchronisableHeader::getSize();
[2662]730    objectOffset=SynchronisableHeader::getSize(); //skip the size and the availableData variables in the objectheader
[7163]731    if ( (*it).objID == oldobjectheader.getObjectID() ){
[2662]732      memcpy(newdata, origdata, objectsize);
733      ++it;
[1907]734    }else{
[2662]735      newobjectheader = oldobjectheader;
[2171]736      memset(newdata+objectOffset, 0, objectsize-objectOffset);
[1907]737    }
738    newdata += objectsize;
739    origdata += objectsize;
[2662]740    destsize += objectsize;
[1907]741  }
[2662]742#ifndef NDEBUG
743  uint32_t origsize = destsize;
[7801]744  while ( origsize < header_.getDataSize() )
[2662]745  {
746    SynchronisableHeader oldobjectheader(origdata);
[7163]747    objectsize = oldobjectheader.getDataSize()+SynchronisableHeader::getSize();
[2662]748    origdata += objectsize;
749    origsize += objectsize;
[1907]750  }
[7801]751  assert(origsize==header_.getDataSize());
[2662]752  assert(destsize!=0);
753#endif
[7801]754  gs->header_.setDataSize( destsize );
[1907]755  return gs;
[7801]756}*/
[1907]757
[2087]758
[7801]759uint32_t Gamestate::calcGamestateSize(uint32_t id, uint8_t mode)
[1701]760{
[7163]761  uint32_t size = 0;
762  uint32_t nrOfVariables = 0;
[1701]763    // get the start of the Synchronisable list
[2171]764  ObjectList<Synchronisable>::iterator it;
[1701]765    // get total size of gamestate
[7163]766  for(it = ObjectList<Synchronisable>::begin(); it; ++it){
[1907]767    size+=it->getSize(id, mode); // size of the actual data of the synchronisable
[7163]768    nrOfVariables += it->getNrOfVariables();
769  }
[8858]770//   orxout() << "allocating " << nrOfVariables << " ints" << endl;
[7163]771  this->sizes_.reserve(nrOfVariables);
[1701]772  return size;
773}
774
[7163]775
[2662]776} //namespace packet
777} //namespace orxonox
Note: See TracBrowser for help on using the repository browser.