Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/GameStateClient.cc @ 1699

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

some missing files

  • Property svn:eol-style set to native
File size: 15.8 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
24 *   Co-authors:
25 *      Dumeni Manatschal
26 *
27 */
28
29#include "GameStateClient.h"
30
31#include <zlib.h>
32
33#include "core/CoreIncludes.h"
34#include "core/BaseObject.h"
35#include "Synchronisable.h"
36#include "packet/Gamestate.h"
37
38namespace network
39{
40  struct GameStateItem{
41    GameState *state;
42    int id;
43  };
44
45  GameStateClient::GameStateClient() {
46    COUT(5) << "this: " << this << std::endl;
47    last_diff_=0;
48    last_gamestate_=GAMESTATEID_INITIAL-1;
49    tempGameState_=NULL;
50    myShip_=NULL;
51  }
52
53  GameStateClient::~GameStateClient() {
54  }
55
56  bool GameStateClient::pushGameState(GameStateCompressed *compstate) {
57    cleanup();
58    printGameStateMap();
59    GameState *gs, *reference;
60    /*if(compstate->id<last_gamestate_){
61      // network packets got messed up
62      COUT(3) << "received an obsolete gamestate" << std::endl;
63      return false;
64    }*/
65    if(compstate->diffed && compstate->base_id!=GAMESTATEID_INITIAL){
66      std::map<int, GameState*>::iterator it = gameStateMap.find(compstate->base_id);
67      if(it!=gameStateMap.end())
68        reference = (it)->second;
69      else
70        reference = NULL;
71      if(!reference){
72        COUT(4) << "pushGameState: no reference found to diff" << std::endl;
73        delete[] compstate->data;
74        delete compstate;
75        return false;
76      }
77      gs = decode(reference, compstate);
78    }
79    else
80      gs = decode(compstate);
81    if(gs){
82      if (loadSnapshot(gs)){
83        gameStateMap.insert(std::pair<int, GameState*>(gs->id, gs));
84        COUT(5) << "adding decoded gs with id: " << gs->id << " diffed from: " << gs->base_id << std::endl;
85        last_diff_=gs->base_id;
86        //last_gamestate_=gs->id;
87        return true;
88      }else{
89        COUT(4) << "could not decode gs with id: " << gs->id << " diffed from: " << gs->base_id << std::endl;
90        delete[] gs->data;
91        delete gs;
92        return false;
93      }
94    }
95    COUT(4) << "could not use gamestate sent by server" << std::endl;
96    return false;
97  }
98
99  GameStateCompressed *GameStateClient::popPartialGameState(){
100    GameState *gs = getPartialSnapshot();
101    if(!gs)
102      return NULL;
103    GameStateCompressed *cgs = compress_(gs);
104    delete[] gs->data;
105    delete gs;
106    return cgs;
107  }
108
109  void GameStateClient::addGameState(GameStateCompressed *gs){
110    if(tempGameState_!=NULL){
111      //delete the obsolete gamestate
112      if(tempGameState_->id>gs->id)
113        return;
114      delete[] tempGameState_->data;
115      delete tempGameState_;
116    }
117    tempGameState_=gs;
118  }
119  int GameStateClient::processGameState(){
120    if(tempGameState_==NULL)
121      return 0;
122    int id=tempGameState_->id;
123    bool b = saveShipCache();
124    if(pushGameState(tempGameState_)){
125      if(b)
126        loadShipCache();
127      packet::Gamestate *g = new packet::Gamestate();
128      if(!g->collectData(1, 0x1))
129        COUT(3) << "problem testing data collecting" << std::endl;
130      else
131      {
132        if(!g->spreadData(0x1))
133          COUT(3) << "problem testing data spreading" << std::endl;
134        delete g;
135      }
136      return id;
137    }
138    else
139      return GAMESTATEID_INITIAL;
140  }
141
142
143  /**
144  * This function removes a Synchronisable out of the universe
145  * @param it iterator of the list pointing to the object
146  * @return iterator pointing to the next object in the list
147  */
148  void GameStateClient::removeObject(orxonox::Iterator<Synchronisable> &it) {
149    orxonox::Iterator<Synchronisable> temp=it;
150    ++it;
151    delete  *temp;
152  }
153
154  /**
155  * This function loads a Snapshort of the gamestate into the universe
156  * @param state a GameState struct containing the size of the gamestate and a pointer linking to a flat list (returned by getSnapshot)
157  */
158  bool GameStateClient::loadSnapshot(GameState *state) {
159    unsigned char *data=state->data;
160    COUT(4) << "loadSnapshot: loading gs: " << state->id << std::endl;
161    // get the start of the Synchronisable list
162    orxonox::Iterator<Synchronisable> it=orxonox::ObjectList<Synchronisable>::start();
163    syncData sync;
164    // loop as long as we have some data ;)
165    while(data < state->data+state->size){
166      // prepare the syncData struct
167      sync.length = *(int *)data;
168      data+=sizeof(int);
169      sync.objectID = *(int*)data;
170      data+=sizeof(int);
171      sync.classID = *(int*)data;
172      data+=sizeof(int);
173      sync.data = data;
174      data+=sync.length;
175
176      if(!it || it->objectID!=sync.objectID){
177        // bad luck ;)
178        // delete the synchronisable (obviously seems to be deleted on the server)
179        while(it && it->objectID!=sync.objectID)
180          removeObject(it);
181
182
183        if(!it){
184          //COUT(4) << "loadSnapshot:\tclassid: " << sync.classID << ", name: " << ID((unsigned int) sync.classID)->getName() << std::endl;
185          ///sigsegv may happen here again for some reason
186          ///sigsegv is receved after the COUT(4) above
187          orxonox::Identifier* id = ID((unsigned int)sync.classID);
188          if(!id){
189            COUT(3) << "We could not identify a new object; classid: " << sync.classID << " uint: " << (unsigned int)sync.classID << " objectID: " << sync.objectID << " size: " << sync.length << std::endl;
190            return false; // most probably the gamestate is corrupted
191          }
192          Synchronisable *no = dynamic_cast<Synchronisable *>(id->fabricate());
193          COUT(4) << "loadsnapshot: classid: " << sync.classID << " objectID: " << sync.objectID << " length: " << sync.length << std::endl;
194          if(!no){
195            COUT(2) << "coudl not frabricate classid: " << sync.classID << " objectID: " << sync.objectID << " identifier: " << id << std::endl;
196            break;
197          }
198          no->objectID=sync.objectID;
199          no->classID=sync.classID;
200          // update data and create object/entity...
201          if( !no->updateData(sync) ){
202            COUT(1) << "We couldn't update the object: " << sync.objectID << std::endl;
203            return false;
204          }
205          if( !no->create() )
206          {
207            COUT(1) << "We couldn't manifest (create() ) the object: " << sync.objectID << std::endl;
208          }
209          it=orxonox::ObjectList<Synchronisable>::end();
210        }
211      } else {
212        // we have our object
213        if(! it->updateData(sync))
214        {
215          COUT(1) << "We couldn't update objectID: " \
216          << sync.objectID << "; classID: " << sync.classID << std::endl;
217        }
218      }
219      ++it;
220    }
221
222    return true;
223  }
224
225  GameState *GameStateClient::getPartialSnapshot(){
226    //std::cout << "begin getSnapshot" << std::endl;
227    //the size of the gamestate
228    int totalsize=0;
229    int memsize=0;
230    //the size of one specific synchronisable
231    int tempsize=0;
232    // get the start of the Synchronisable list
233    orxonox::Iterator<Synchronisable> it;
234    // struct for return value of Synchronisable::getData()
235    syncData sync;
236
237    GameState *retval=new GameState; //return value
238//     retval->id=reference->id;
239    if(gameStateMap.size()!=0)
240      retval->id=(--gameStateMap.end())->second->id;
241    retval->diffed=false;
242    retval->complete=false;
243    COUT(4) << "G.ST.Client: producing partial gamestate with id: " << retval->id << std::endl;
244    // offset of memory functions
245    int offset=0, size=0;
246    // get total size of gamestate
247    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
248      if(!it->getBacksync())
249        continue;
250      size+=it->getSize(); // size of the actual data of the synchronisable
251      size+=3*sizeof(int); // size of datasize, classID and objectID
252      COUT(5) << "getpartialsnapshot: size: " << size << std::endl;
253    }
254    //retval->data = (unsigned char*)malloc(size);
255    if(size==0)
256      return NULL;
257    retval->data = new unsigned char[size];
258    if(!retval->data){
259      COUT(2) << "GameStateClient: could not allocate memory" << std::endl;
260      return NULL;
261    }
262    memsize=size;
263    // go through all Synchronisables
264    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
265      if(!it->getBacksync())
266        continue;
267      //get size of the synchronisable
268      tempsize=it->getSize();
269      // add place for data and 3 ints (length,classid,objectid)
270      totalsize+=tempsize+3*sizeof(int);
271      // allocate+tempsize additional space
272      if(totalsize > size){
273        COUT(3) << "G.St.Cl: need additional memory" << std::endl;
274      }
275
276      // run Synchronisable::getData with offset and additional place for 3 ints in between (for ids and length)
277      sync=it->getData((retval->data)+offset+3*sizeof(int));
278      memcpy(retval->data+offset, (void *)&(sync.length), sizeof(int));
279      memcpy(retval->data+offset+sizeof(int), (void *)&(sync.objectID), sizeof(int));
280      memcpy(retval->data+offset+2*sizeof(int), (void *)&(sync.classID), sizeof(int));
281      // increase data pointer
282      offset+=tempsize+3*sizeof(int);
283    }
284    retval->size=totalsize;
285    COUT(5) << "G.ST.Cl: Gamestate size: " << totalsize << std::endl;
286    COUT(5) << "G.ST.Cl: 'estimated' Gamestate size: " << size << std::endl;
287    return retval;
288  }
289
290
291  GameState *GameStateClient::undiff(GameState *old, GameState *diff) {
292    if(!old || !diff)
293      return NULL;
294    unsigned char *ap = old->data, *bp = diff->data;
295    int of=0; // pointers offset
296    int dest_length=0;
297    /*if(old->size>=diff->size)
298      dest_length=old->size;
299    else*/
300      dest_length=diff->size;
301//     unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));
302    if(dest_length==0)
303      return NULL;
304    unsigned char *dp = new unsigned char[dest_length*sizeof(unsigned char)];
305    while(of<old->size && of<diff->size){
306      *(dp+of)=*(ap+of)^*(bp+of); // do the xor
307      ++of;
308    }
309    if(old->size!=diff->size){ // do we have to fill up ?
310      unsigned char n=0;
311      if(old->size<diff->size){
312        while(of<dest_length){
313          *(dp+of)=n^*(bp+of);
314          of++;
315        }
316      } /*else{
317        while(of<dest_length){
318          *(dp+of)=*(ap+of)^n;
319          of++;
320        }
321      }*/
322    }
323    // should be finished now
324    // FIXME: is it true or false now? (struct has changed, producing warnings)
325    GameState *r = new GameState;
326    r->id = diff->id;
327    r->size = dest_length;
328    r->base_id = old->id;
329    r->diffed = false;
330    r->data = dp;
331    r->complete = true;
332    return r;
333  }
334
335
336
337  GameStateCompressed *GameStateClient::compress_(GameState *a) {
338    if(!a)
339      return NULL;
340    int size = a->size;
341
342    uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;
343    if(buffer==0)
344      return NULL;
345    unsigned char *dest = new unsigned char[buffer];
346    int retval;
347    retval = compress( dest, &buffer, a->data, (uLong)size );
348
349    switch ( retval ) {
350      case Z_OK: COUT(5) << "G.St.Cl: compress: successfully compressed" << std::endl; break;
351      case Z_MEM_ERROR: COUT(1) << "G.St.Cl: compress: not enough memory available in gamestate.compress" << std::endl;
352      return NULL;
353      case Z_BUF_ERROR: COUT(2) << "G.St.Cl: compress: not enough memory available in the buffer in gamestate.compress" << std::endl;
354      return NULL;
355      case Z_DATA_ERROR: COUT(2) << "G.St.Cl: compress: data corrupted in gamestate.compress" << std::endl;
356      return NULL;
357    }
358
359    GameStateCompressed *compressedGamestate = new GameStateCompressed;
360    compressedGamestate->compsize = buffer;
361    compressedGamestate->normsize = size;
362    compressedGamestate->id = a->id;
363    compressedGamestate->data = dest;
364    compressedGamestate->diffed = a->diffed;
365    compressedGamestate->complete = a->complete;
366    compressedGamestate->base_id = a->base_id;
367    return compressedGamestate;
368  }
369
370
371  GameState *GameStateClient::decompress(GameStateCompressed *a) {
372    //COUT(4) << "GameStateClient: uncompressing gamestate. id: " << a->id << ", baseid: " << a->base_id << ", normsize: " << a->normsize << ", compsize: " << a->compsize << std::endl;
373    int normsize = a->normsize;
374    int compsize = a->compsize;
375    int bufsize;
376    if(normsize < compsize)
377      bufsize = compsize;
378    else
379      bufsize = normsize;
380//     unsigned char* dest = (unsigned char*)malloc( bufsize );
381    if(bufsize==0)
382      return NULL;
383    unsigned char *dest = new unsigned char[bufsize];
384    int retval;
385    uLongf length=normsize;
386    //std::cout << "gamestateclient" << std::endl;
387    //std::cout << "normsize " << a.normsize << " compsize " << a.compsize << " " << bufsize << std::endl;
388    retval = uncompress( dest, &length, a->data, (uLong)compsize );
389    //std::cout << "length " << length << std::endl;
390    switch ( retval ) {
391      case Z_OK: COUT(5) << "successfully decompressed" << std::endl; break;
392      case Z_MEM_ERROR: COUT(1) << "not enough memory available" << std::endl; return NULL;
393      case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer" << std::endl; return NULL;
394      case Z_DATA_ERROR: COUT(2) << "data corrupted (zlib)" << std::endl; return NULL;
395    }
396
397    GameState *gamestate = new GameState;
398    gamestate->id = a->id;
399    gamestate->size = normsize;
400    gamestate->data = dest;
401    gamestate->base_id = a->base_id;
402    gamestate->diffed = a->diffed;
403    gamestate->complete = a->complete;
404
405
406    return gamestate;
407  }
408
409  GameState *GameStateClient::decode(GameState *old, GameStateCompressed *diff) {
410    COUT(5) << "using diffed gamestate" << std::endl;
411    GameState *t = decode(diff);
412    if(!t)
413      return NULL;
414    GameState *r = undiff(old, t);
415    delete[] t->data;
416    delete t;
417    return r;
418  }
419
420  GameState *GameStateClient::decode(GameStateCompressed *x) {
421    GameState *t = decompress(x);
422    delete[] x->data;
423    delete x;
424    return t;
425  }
426
427  void GameStateClient::cleanup(){
428    std::map<int, GameState*>::iterator temp, it = gameStateMap.begin();
429    while(it!=gameStateMap.end()){
430      if(it->first>=last_diff_)
431        break;
432      // otherwise delete that stuff
433      delete[] (*it).second->data;
434      delete (*it).second;
435      temp=it++;
436      gameStateMap.erase(temp);
437    }
438    tempGameState_=NULL;
439  }
440
441  void GameStateClient::printGameStateMap(){
442    std::map<int, GameState*>::iterator it;
443    COUT(4) << "gamestates: ";
444    for(it=gameStateMap.begin(); it!=gameStateMap.end(); it++){
445      COUT(4) << it->first << ":" << it->second << "|";
446    }
447    COUT(4) << std::endl;
448
449  }
450
451  bool GameStateClient::saveShipCache(){
452    if(myShip_==NULL)
453      myShip_ = orxonox::SpaceShip::getLocalShip();
454    if(myShip_){
455      //      unsigned char *data = new unsigned char[myShip_->getSize()];
456      int size=myShip_->getSize(0x3);
457      if(size==0)
458        return false;
459      unsigned char *data = new unsigned char [size];
460      shipCache_ = myShip_->getData(data, 0x1);
461      return true;
462    }else
463      return false;
464  }
465
466  bool GameStateClient::loadShipCache(){
467    if(myShip_){
468      myShip_->updateData(shipCache_, 0x2);
469      if(shipCache_.data){
470        delete[] shipCache_.data;
471      }
472      return true;
473    }else
474      return false;
475  }
476
477    //##### ADDED FOR TESTING PURPOSE #####
478  GameState* GameStateClient::testDecompress( GameStateCompressed* gc ) {
479    return decompress( gc );
480  }
481
482  GameState* GameStateClient::testUndiff( GameState* g_old, GameState* g_diffed ) {
483    return undiff( g_old, g_diffed );
484  }
485  //##### ADDED FOR TESTING PURPOSE #####
486
487
488}
489
Note: See TracBrowser for help on using the repository browser.