Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

further changes

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->normsize = currentsize;
83  HEADER->id = id;
84  HEADER->diffed = false;
85  HEADER->complete = true;
86  compressed_=false;
87  //stop write gamestate header
88 
89  COUT(5) << "G.ST.Man: Gamestate size: " << currentsize << std::endl;
90  COUT(5) << "G.ST.Man: 'estimated' (and corrected) Gamestate size: " << size << std::endl;
91  return true;
92}
93
94bool Gamestate::spreadData(int mode)
95{
96  assert(data_ && !compressed_ && !HEADER->diffed);
97  unsigned int size, objectID, classID;
98  unsigned char *mem=data_+sizeof(GamestateHeader);
99    // get the start of the Synchronisable list
100  orxonox::Iterator<Synchronisable> it=orxonox::ObjectList<Synchronisable>::start();
101 
102  while(mem < data_+sizeof(GamestateHeader)+HEADER->normsize){
103      // extract synchronisable header
104    size = *(int *)mem;
105    objectID = *(int*)(mem+sizeof(int));
106    classID = *(int*)(mem+2*sizeof(int));
107
108    if(!it || it->objectID!=objectID){
109        // bad luck ;)
110        // delete the synchronisable (obviously seems to be deleted on the server)
111      while(it && it->objectID!=objectID)
112        removeObject(it);
113
114      if(!it){
115        //fabricate the new synchronisable
116        if(!Synchronisable::fabricate(mem, mode))
117          return false;
118        it=orxonox::ObjectList<Synchronisable>::end();
119      }
120    } else 
121    {
122        // we have our object
123      if(! it->updateData(mem, mode))
124      {
125        COUT(1) << "We couldn't update objectID: " \
126            << objectID << "; classID: " << classID << std::endl;
127      }
128    }
129    ++it;
130  }
131
132  return true;
133}
134
135int Gamestate::getID(){
136  return HEADER->id;
137}
138
139unsigned char *Gamestate::getData()
140{
141  assert(data_!=0);
142  return data_;
143}
144
145unsigned int Gamestate::getSize() const
146{
147  if(compressed_)
148    return HEADER->compsize+sizeof(GamestateHeader);
149  else
150  {
151    return HEADER->normsize+sizeof(GamestateHeader);
152  }
153}
154
155bool Gamestate::process()
156{
157  return GamestateHandler::addGamestate(this, getClientID());
158}
159
160bool Gamestate::compressData()
161{
162  assert(HEADER);
163  uLongf buffer = (uLongf)((HEADER->normsize + 12)*1.01)+1;
164  if(buffer==0)
165    return false;
166 
167  unsigned char *ndata = new unsigned char[buffer+sizeof(GamestateHeader)];
168  unsigned char *dest = GAMESTATE_START(ndata);
169  int retval;
170  retval = compress( dest, &buffer, GAMESTATE_START(data_), (uLong)(HEADER->normsize) );
171  switch ( retval ) {
172    case Z_OK: COUT(5) << "G.St.Man: compress: successfully compressed" << std::endl; break;
173    case Z_MEM_ERROR: COUT(1) << "G.St.Man: compress: not enough memory available in gamestate.compress" << std::endl; 
174    return false;
175    case Z_BUF_ERROR: COUT(2) << "G.St.Man: compress: not enough memory available in the buffer in gamestate.compress" << std::endl;
176    return false;
177    case Z_DATA_ERROR: COUT(2) << "G.St.Man: compress: data corrupted in gamestate.compress" << std::endl;
178    return false;
179  }
180
181  //copy and modify header
182  HEADER->compsize = buffer;
183  *GAMESTATE_HEADER(ndata) = *HEADER;
184  //delete old data
185  delete[] data_;
186  //save new data
187  data_ = ndata;
188  compressed_ = true;
189  return true;
190}
191bool Gamestate::decompressData()
192{
193  //COUT(4) << "GameStateClient: uncompressing gamestate. id: " << a->id << ", baseid: " << a->base_id << ", normsize: " << a->normsize << ", compsize: " << a->compsize << std::endl;
194  int normsize = HEADER->normsize;
195  int compsize = HEADER->compsize;
196  int bufsize;
197  if(normsize < compsize)
198    bufsize = compsize;
199  else
200    bufsize = normsize;
201  if(bufsize==0)
202    return NULL;
203  unsigned char *ndata = new unsigned char[bufsize + sizeof(GamestateHeader)];
204  unsigned char *dest = ndata + sizeof(GamestateHeader);
205  int retval;
206  uLongf length=normsize;
207  retval = uncompress( dest, &length, data_+sizeof(GamestateHeader), (uLong)compsize );
208  switch ( retval ) {
209    case Z_OK: COUT(5) << "successfully decompressed" << std::endl; break;
210    case Z_MEM_ERROR: COUT(1) << "not enough memory available" << std::endl; return false;
211    case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer" << std::endl; return false;
212    case Z_DATA_ERROR: COUT(2) << "data corrupted (zlib)" << std::endl; return false;
213  }
214 
215  compressed_ = false;
216  //copy over the header
217  *GAMESTATE_HEADER(ndata) = *HEADER;
218  //delete old (compressed data)
219  delete []data_;
220  //set new pointers and create bytestream
221  data_ = ndata;
222  //bs_ = new Bytestream(getGs(), GAMESTATE_HEADER->normsize);
223 
224  return true;
225}
226
227Gamestate *Gamestate::diff(Gamestate *base)
228{
229  //unsigned char *basep = base->getGs()/*, *gs = getGs()*/;
230  unsigned char *basep = GAMESTATE_START(base->data_), *gs = GAMESTATE_START(this->data_);
231  unsigned int of=0; // pointers offset
232  unsigned int dest_length=0;
233  dest_length=HEADER->normsize;
234  if(dest_length==0)
235    return NULL;
236  unsigned char *ndata = new unsigned char[dest_length*sizeof(unsigned char)+sizeof(GamestateHeader)];
237  unsigned char *dest = ndata + sizeof(GamestateHeader);
238  while(of < GAMESTATE_HEADER(base->data_)->normsize && of < HEADER->normsize){
239    *(dest+of)=*(basep+of)^*(gs+of); // do the xor
240    ++of;
241  }
242  if(GAMESTATE_HEADER(base->data_)->normsize!=HEADER->normsize){
243    unsigned char n=0;
244    if(GAMESTATE_HEADER(base->data_)->normsize < HEADER->normsize){
245      while(of<dest_length){
246        *(dest+of)=n^*(gs+of);
247        of++;
248      }
249    }
250  }
251
252  Gamestate *g = new Gamestate(ndata, false, 0);
253  return g;
254}
255
256Gamestate *Gamestate::undiff(Gamestate *base)
257{
258  assert(this && base);
259  assert(!this->compressed_ && !base->compressed_);
260  //unsigned char *basep = base->getGs()/*, *gs = getGs()*/;
261  unsigned char *basep = GAMESTATE_START(base->data_);
262  unsigned char *gs = GAMESTATE_START(this->data_);
263  unsigned int of=0; // pointers offset
264  unsigned int dest_length=0;
265  dest_length=HEADER->normsize;
266  if(dest_length==0)
267    return NULL;
268  unsigned char *ndata = new unsigned char[dest_length*sizeof(unsigned char)+sizeof(GamestateHeader)];
269  unsigned char *dest = ndata + sizeof(GamestateHeader);
270  while(of < GAMESTATE_HEADER(base->data_)->normsize && of < HEADER->normsize){
271    *(dest+of)=*(basep+of)^*(gs+of); // do the xor
272    ++of;
273  }
274  if(GAMESTATE_HEADER(base->data_)->normsize!=HEADER->normsize){
275    unsigned char n=0;
276    if(GAMESTATE_HEADER(base->data_)->normsize < HEADER->normsize){
277      while(of < dest_length){
278        *(dest+of)=n^*(gs+of);
279        of++;
280      }
281    }
282  }
283 
284  Gamestate *g = new Gamestate(ndata, false, 0);
285  return g;
286}
287
288
289unsigned int Gamestate::calcGamestateSize(int mode)
290{
291  int size=0;
292    // get the start of the Synchronisable list
293  orxonox::Iterator<Synchronisable> it;
294    // get total size of gamestate
295  for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it)
296    size+=it->getSize2(mode); // size of the actual data of the synchronisable
297//  size+=sizeof(GamestateHeader);
298  return size;
299}
300
301/**
302 * This function removes a Synchronisable out of the universe
303 * @param it iterator of the list pointing to the object
304 * @return iterator pointing to the next object in the list
305 */
306  void Gamestate::removeObject(orxonox::Iterator<Synchronisable> &it) {
307    orxonox::Iterator<Synchronisable> temp=it;
308    ++it;
309    delete  *temp;
310  }
311
312}
313
314}
Note: See TracBrowser for help on using the repository browser.