Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

further errors corrected (mostly double frees, etc)

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