Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/Masterserver_FS18/src/libraries/network/packet/Gamestate.cc @ 11858

Last change on this file since 11858 was 11858, checked in by varyo, 6 years ago

added 2nd multiplayer test map (Basically Last Team Standing, but all asteroids removed), fixed first one(removed comments in lua file, seemed to have messed with SpawnPoints), added few comments in Gamestate.cc

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