Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/packet/Gamestate.cc @ 1741

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

compressing doesnt work yet (maybe rather decompressing)

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