Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

another one bites the dust: solved that problem with zeros in the gamestate

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