Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network3/src/network/GameStateClient.cc @ 1242

Last change on this file since 1242 was 1232, checked in by scheusso, 17 years ago

a lot of changes in order to make it possible to have mulpiple clients with each one a new ship
camera changes
object changes
synchronisable: backsyncronisation should be possible now
gamestatemanager/gamestateclient: functions for backsyncronisation
some changes in order to get the input system (the old one) on the client working
TODO something with the camera position is wrong at the moment (clientside)

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