Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

we use enetcallback for destroying packets now (unfortunately there are still some problems)

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