Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

enet callback disabled

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