Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

problems of the merge should be solved now (hopefully)

  • Property svn:eol-style set to native
File size: 12.2 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:
23 *      Oliver Scheuss, (C) 2008
24 *   Co-authors:
25 *      ...
26 *
27 */
28
[1701]29#include "Gamestate.h"
30#include "network/ClientInformation.h"
[1705]31#include "network/GamestateHandler.h"
[1763]32#include "core/CoreIncludes.h"
[1751]33#include "core/Iterator.h"
[1701]34
35#include <zlib.h>
36#include <assert.h>
37
38
39
40namespace network {
41
42namespace packet {
43
[1751]44#define GAMESTATE_START(data) (data + sizeof(GamestateHeader))
[1701]45#define GAMESTATE_HEADER(data) ((GamestateHeader *)data)
46#define HEADER GAMESTATE_HEADER(data_)
[1740]47
[1701]48Gamestate::Gamestate()
49{
50}
51
[1715]52Gamestate::Gamestate(unsigned char *data, int clientID):
[1711]53    Packet(data, clientID)
[1701]54{
55}
56
57
58Gamestate::~Gamestate()
59{
60}
61
62bool Gamestate::collectData(int id, int mode)
63{
64  int tempsize=0, currentsize=0;
[1751]65  assert(data_==0);
66  int size = calcGamestateSize(id, mode);
[1740]67
[1701]68  COUT(4) << "G.ST.Man: producing gamestate with id: " << id << std::endl;
69  if(size==0)
70    return false;
71  data_ = new unsigned char[size + sizeof(GamestateHeader)];
72  if(!data_){
73    COUT(2) << "GameStateManager: could not allocate memory" << std::endl;
74    return false;
75  }
76
77  //start collect data synchronisable by synchronisable
78  unsigned char *mem=data_;
79  mem+=sizeof(GamestateHeader);
[1747]80  orxonox::ObjectList<Synchronisable>::iterator it;
81  for(it = orxonox::ObjectList<Synchronisable>::begin(); it; ++it){
[1751]82    tempsize=it->getSize2(id, mode);
[1740]83
[1701]84    if(currentsize+tempsize > size){
85      // start allocate additional memory
86      COUT(3) << "G.St.Man: need additional memory" << std::endl;
[1747]87      orxonox::ObjectList<Synchronisable>::iterator temp = it;
[1701]88      int addsize=tempsize;
89      while(++temp)
[1751]90        addsize+=temp->getSize2(id, mode);
[1701]91      data_ = (unsigned char *)realloc(data_, sizeof(GamestateHeader) + currentsize + addsize);
92      if(!data_)
93        return false;
94      size = currentsize+addsize;
95    }// stop allocate additional memory
96
[1751]97    if(!it->getData(mem, id, mode))
[1701]98      return false; // mem pointer gets automatically increased because of call by reference
99    // increase size counter by size of current synchronisable
100    currentsize+=tempsize;
101  }
[1740]102
103
[1701]104  //start write gamestate header
[1710]105  HEADER->packetType = ENUM::Gamestate;
[1740]106  assert( *(ENUM::Type *)(data_) == ENUM::Gamestate);
[1701]107  HEADER->normsize = currentsize;
108  HEADER->id = id;
109  HEADER->diffed = false;
110  HEADER->complete = true;
[1715]111  HEADER->compressed = false;
[1701]112  //stop write gamestate header
[1740]113
[1701]114  COUT(5) << "G.ST.Man: Gamestate size: " << currentsize << std::endl;
115  COUT(5) << "G.ST.Man: 'estimated' (and corrected) Gamestate size: " << size << std::endl;
116  return true;
117}
118
119bool Gamestate::spreadData(int mode)
120{
[1751]121  assert(data_);
122  assert(!HEADER->compressed);
123  assert(!HEADER->diffed);
[1701]124  unsigned int size, objectID, classID;
125  unsigned char *mem=data_+sizeof(GamestateHeader);
126    // get the start of the Synchronisable list
[1747]127  orxonox::ObjectList<Synchronisable>::iterator it=orxonox::ObjectList<Synchronisable>::begin();
[1740]128
[1701]129  while(mem < data_+sizeof(GamestateHeader)+HEADER->normsize){
130      // extract synchronisable header
[1730]131    size = *(unsigned int *)mem;
132    objectID = *(unsigned int*)(mem+sizeof(unsigned int));
133    classID = *(unsigned int*)(mem+2*sizeof(unsigned int));
[1701]134
[1730]135    if(!it || it->objectID!=objectID || it->classID!=classID){
[1701]136        // bad luck ;)
137        // delete the synchronisable (obviously seems to be deleted on the server)
138      while(it && it->objectID!=objectID)
139        removeObject(it);
140
141      if(!it){
142        //fabricate the new synchronisable
143        if(!Synchronisable::fabricate(mem, mode))
[1751]144          return false;
[1701]145        it=orxonox::ObjectList<Synchronisable>::end();
[1767]146      }else{
147        if(! it->updateData(mem, mode))
148        {
149          COUT(1) << "We couldn't update objectID: " \
150            << objectID << "; classID: " << classID << std::endl;
151        }
[1701]152      }
[1740]153    } else
[1701]154    {
155        // we have our object
156      if(! it->updateData(mem, mode))
157      {
158        COUT(1) << "We couldn't update objectID: " \
159            << objectID << "; classID: " << classID << std::endl;
160      }
161    }
162    ++it;
163  }
164
165  return true;
166}
167
[1705]168int Gamestate::getID(){
169  return HEADER->id;
170}
171
[1701]172unsigned int Gamestate::getSize() const
173{
[1711]174  assert(data_);
[1715]175  if(HEADER->compressed)
[1701]176    return HEADER->compsize+sizeof(GamestateHeader);
177  else
178  {
179    return HEADER->normsize+sizeof(GamestateHeader);
180  }
181}
182
[1751]183bool Gamestate::operator==(packet::Gamestate gs){
184  unsigned char *d1 = data_+sizeof(GamestateHeader);
185  unsigned char *d2 = gs.data_+sizeof(GamestateHeader);
186  assert(!isCompressed());
187  assert(!gs.isCompressed());
188  while(d1<data_+HEADER->normsize)
189  {
190    if(*d1!=*d2)
191      return false;
192    d1++;
193    d2++;
194  }
195  return true;
196}
197
[1701]198bool Gamestate::process()
199{
[1705]200  return GamestateHandler::addGamestate(this, getClientID());
[1701]201}
202
203bool Gamestate::compressData()
204{
205  assert(HEADER);
[1751]206  assert(!HEADER->compressed);
207  uLongf buffer = (uLongf)(((HEADER->normsize + 12)*1.01)+1);
[1701]208  if(buffer==0)
209    return false;
[1740]210
[1701]211  unsigned char *ndata = new unsigned char[buffer+sizeof(GamestateHeader)];
212  unsigned char *dest = GAMESTATE_START(ndata);
[1751]213  //unsigned char *dest = new unsigned char[buffer];
214  unsigned char *source = GAMESTATE_START(data_);
[1701]215  int retval;
[1751]216  retval = compress( dest, &buffer, source, (uLong)(HEADER->normsize) );
[1701]217  switch ( retval ) {
218    case Z_OK: COUT(5) << "G.St.Man: compress: successfully compressed" << std::endl; break;
[1751]219    case Z_MEM_ERROR: COUT(1) << "G.St.Man: compress: not enough memory available in gamestate.compress" << std::endl; return false;
220    case Z_BUF_ERROR: COUT(2) << "G.St.Man: compress: not enough memory available in the buffer in gamestate.compress" << std::endl; return false;
221    case Z_DATA_ERROR: COUT(2) << "G.St.Man: compress: data corrupted in gamestate.compress" << std::endl; return false;
[1701]222  }
[1751]223#ifndef NDEBUG
224  //decompress and compare the start and the decompressed data
225  unsigned char *rdata = new unsigned char[HEADER->normsize+sizeof(GamestateHeader)];
226  unsigned char *d2 = GAMESTATE_START(rdata);
227  uLongf length2 = HEADER->normsize;
228  uncompress(d2, &length2, dest, buffer);
229  for(unsigned int i=0; i<HEADER->normsize; i++){
230    assert(*(source+i)==*(d2+i));
231  }
232  delete[] rdata;
233#endif
[1701]234
235  //copy and modify header
[1751]236#ifndef NDEBUG
237  HEADER->crc32 = calcCRC(data_+sizeof(GamestateHeader), HEADER->normsize);
238#endif
[1701]239  *GAMESTATE_HEADER(ndata) = *HEADER;
240  //delete old data
241  delete[] data_;
242  //save new data
243  data_ = ndata;
[1751]244  HEADER->compsize = buffer;
245  HEADER->compressed = true;
[1730]246  assert(HEADER->compressed);
247  COUT(3) << "gamestate compress normsize: " << HEADER->normsize << " compsize: " << HEADER->compsize << std::endl;
[1701]248  return true;
249}
250bool Gamestate::decompressData()
251{
[1751]252  assert(HEADER);
[1715]253  assert(HEADER->compressed);
[1751]254  COUT(3) << "GameStateClient: uncompressing gamestate. id: " << HEADER->id << ", baseid: " << HEADER->base_id << ", normsize: " << HEADER->normsize << ", compsize: " << HEADER->compsize << std::endl;
255  unsigned int normsize = HEADER->normsize;
256  unsigned int compsize = HEADER->compsize;
257  unsigned int bufsize;
258  assert(compsize<=normsize);
259  bufsize = normsize;
260  assert(bufsize!=0);
[1701]261  unsigned char *ndata = new unsigned char[bufsize + sizeof(GamestateHeader)];
262  unsigned char *dest = ndata + sizeof(GamestateHeader);
[1751]263  unsigned char *source = data_ + sizeof(GamestateHeader);
[1701]264  int retval;
[1751]265  uLongf length=bufsize;
266  retval = uncompress( dest, &length, source, (uLong)compsize );
[1701]267  switch ( retval ) {
268    case Z_OK: COUT(5) << "successfully decompressed" << std::endl; break;
269    case Z_MEM_ERROR: COUT(1) << "not enough memory available" << std::endl; return false;
270    case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer" << std::endl; return false;
271    case Z_DATA_ERROR: COUT(2) << "data corrupted (zlib)" << std::endl; return false;
272  }
[1751]273#ifndef NDEBUG
274  assert(HEADER->crc32==calcCRC(ndata+sizeof(GamestateHeader), HEADER->normsize));
275#endif
[1752]276
[1701]277  //copy over the header
278  *GAMESTATE_HEADER(ndata) = *HEADER;
279  //delete old (compressed data)
[1712]280  delete[] data_;
[1751]281  //set new pointers
[1701]282  data_ = ndata;
[1751]283  HEADER->compressed = false;
284  assert(HEADER->normsize==normsize);
285  assert(HEADER->compsize==compsize);
[1701]286  return true;
287}
288
289Gamestate *Gamestate::diff(Gamestate *base)
290{
[1751]291  assert(HEADER);
292  assert(!HEADER->compressed);
293  assert(!HEADER->diffed);
[1701]294  //unsigned char *basep = base->getGs()/*, *gs = getGs()*/;
295  unsigned char *basep = GAMESTATE_START(base->data_), *gs = GAMESTATE_START(this->data_);
296  unsigned int of=0; // pointers offset
297  unsigned int dest_length=0;
298  dest_length=HEADER->normsize;
299  if(dest_length==0)
300    return NULL;
301  unsigned char *ndata = new unsigned char[dest_length*sizeof(unsigned char)+sizeof(GamestateHeader)];
302  unsigned char *dest = ndata + sizeof(GamestateHeader);
303  while(of < GAMESTATE_HEADER(base->data_)->normsize && of < HEADER->normsize){
304    *(dest+of)=*(basep+of)^*(gs+of); // do the xor
305    ++of;
306  }
307  if(GAMESTATE_HEADER(base->data_)->normsize!=HEADER->normsize){
308    unsigned char n=0;
309    if(GAMESTATE_HEADER(base->data_)->normsize < HEADER->normsize){
310      while(of<dest_length){
311        *(dest+of)=n^*(gs+of);
312        of++;
313      }
314    }
315  }
316
[1715]317  *GAMESTATE_HEADER(ndata) = *HEADER;
318  GAMESTATE_HEADER(ndata)->diffed = true;
[1751]319  GAMESTATE_HEADER(ndata)->base_id = base->getID();
320  Gamestate *g = new Gamestate(ndata, getClientID());
321  g->flags_=flags_;
322  g->packetDirection_ = packetDirection_;
[1701]323  return g;
324}
325
326Gamestate *Gamestate::undiff(Gamestate *base)
327{
[1751]328  assert(this && base);assert(HEADER);
329  assert(HEADER->diffed);
[1715]330  assert(!HEADER->compressed && !GAMESTATE_HEADER(base->data_)->compressed);
[1701]331  //unsigned char *basep = base->getGs()/*, *gs = getGs()*/;
332  unsigned char *basep = GAMESTATE_START(base->data_);
333  unsigned char *gs = GAMESTATE_START(this->data_);
334  unsigned int of=0; // pointers offset
335  unsigned int dest_length=0;
336  dest_length=HEADER->normsize;
337  if(dest_length==0)
338    return NULL;
339  unsigned char *ndata = new unsigned char[dest_length*sizeof(unsigned char)+sizeof(GamestateHeader)];
340  unsigned char *dest = ndata + sizeof(GamestateHeader);
341  while(of < GAMESTATE_HEADER(base->data_)->normsize && of < HEADER->normsize){
342    *(dest+of)=*(basep+of)^*(gs+of); // do the xor
343    ++of;
344  }
345  if(GAMESTATE_HEADER(base->data_)->normsize!=HEADER->normsize){
346    unsigned char n=0;
347    if(GAMESTATE_HEADER(base->data_)->normsize < HEADER->normsize){
348      while(of < dest_length){
349        *(dest+of)=n^*(gs+of);
350        of++;
351      }
352    }
353  }
[1715]354  *GAMESTATE_HEADER(ndata) = *HEADER;
355  GAMESTATE_HEADER(ndata)->diffed = false;
[1751]356  Gamestate *g = new Gamestate(ndata, getClientID());
357  g->flags_=flags_;
358  g->packetDirection_ = packetDirection_;
359  assert(!g->isDiffed());
360  assert(!g->isCompressed());
[1701]361  return g;
362}
363
364
[1751]365unsigned int Gamestate::calcGamestateSize(unsigned int id, int mode)
[1701]366{
367  int size=0;
368    // get the start of the Synchronisable list
[1747]369  orxonox::ObjectList<Synchronisable>::iterator it;
[1701]370    // get total size of gamestate
[1747]371  for(it = orxonox::ObjectList<Synchronisable>::begin(); it; ++it)
[1751]372    size+=it->getSize2(id, mode); // size of the actual data of the synchronisable
[1701]373//  size+=sizeof(GamestateHeader);
374  return size;
375}
376
377/**
378 * This function removes a Synchronisable out of the universe
379 * @param it iterator of the list pointing to the object
380 * @return iterator pointing to the next object in the list
381 */
[1747]382  void Gamestate::removeObject(orxonox::ObjectList<Synchronisable>::iterator &it) {
383    orxonox::ObjectList<Synchronisable>::iterator temp=it;
[1701]384    ++it;
385    delete  *temp;
386  }
387
[1712]388  bool Gamestate::isDiffed(){
389    return HEADER->diffed;
390  }
[1740]391
[1751]392  bool Gamestate::isCompressed(){
393    return HEADER->compressed;
394  }
[1752]395
[1712]396  int Gamestate::getBaseID(){
397    return HEADER->base_id;
398  }
[1701]399}
400
401}
Note: See TracBrowser for help on using the repository browser.