Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1226 was 1200, checked in by scheusso, 17 years ago

we have compression enabled and working now, hurray

File size: 9.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  /**
90  * This function removes a Synchronisable out of the universe
91  * @param it iterator of the list pointing to the object
92  * @return iterator pointing to the next object in the list
93  */
94  void GameStateClient::removeObject(orxonox::Iterator<Synchronisable> &it) {
95    orxonox::Iterator<Synchronisable> temp=it;
96    ++it;
97    delete  *temp;
98  }
99
100  /**
101  * This function loads a Snapshort of the gamestate into the universe
102  * @param state a GameState struct containing the size of the gamestate and a pointer linking to a flat list (returned by getSnapshot)
103  */
104  bool GameStateClient::loadSnapshot(GameState *state) {
105    unsigned char *data=state->data;
106    COUT(4) << "loadSnapshot: loading gs: " << state->id << std::endl;
107    // get the start of the Synchronisable list
108    orxonox::Iterator<Synchronisable> it=orxonox::ObjectList<Synchronisable>::start();
109    syncData sync;
110    // loop as long as we have some data ;)
111    while(data < state->data+state->size){
112      // prepare the syncData struct
113      sync.length = *(int *)data;
114      data+=sizeof(int);
115      sync.objectID = *(int*)data;
116      data+=sizeof(int);
117      sync.classID = *(int*)data;
118      data+=sizeof(int);
119      sync.data = data;
120      data+=sync.length;
121
122      if(!it || it->objectID!=sync.objectID){
123        // bad luck ;)
124        // delete the synchronisable (obviously seems to be deleted on the server)
125        while(it && it->objectID!=sync.objectID)
126          removeObject(it);
127
128
129        if(!it){
130          //COUT(4) << "loadSnapshot:\tclassid: " << sync.classID << ", name: " << ID((unsigned int) sync.classID)->getName() << std::endl;
131          ///sigsegv may happen here again for some reason
132          ///sigsegv is receved after the COUT(4) above
133          orxonox::Identifier* id = ID((unsigned int)sync.classID);
134          if(!id){
135            COUT(4) << "We could not identify a new object; classid: " << sync.classID << std::endl;
136            continue;
137          }
138          Synchronisable *no = dynamic_cast<Synchronisable *>(id->fabricate());
139          COUT(4) << "loadsnapshort: classid: " << sync.classID << " objectID: " << sync.objectID << " length: " << sync.length << std::endl;
140          no->objectID=sync.objectID;
141          no->classID=sync.classID;
142          it=orxonox::ObjectList<Synchronisable>::end();
143          // update data and create object/entity...
144          if( !no->updateData(sync) )
145            COUT(1) << "We couldn't update the object: " << sync.objectID << std::endl;
146          if( !no->create() )
147            COUT(1) << "We couldn't manifest (create() ) the object: " << sync.objectID << std::endl;
148        }
149      } else {
150        // we have our object
151        if(! it->updateData(sync))
152          COUT(1) << "We couldn't update objectID: " \
153          << sync.objectID << "; classID: " << sync.classID << std::endl;
154      }
155      ++it;
156    }
157
158    return true;
159  }
160
161  GameState *GameStateClient::undiff(GameState *old, GameState *diff) {
162    unsigned char *ap = old->data, *bp = diff->data;
163    int of=0; // pointers offset
164    int dest_length=0;
165    if(old->size>=diff->size)
166      dest_length=old->size;
167    else
168      dest_length=diff->size;
169//     unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));
170    unsigned char *dp = new unsigned char[dest_length*sizeof(unsigned char)];
171    while(of<old->size && of<diff->size){
172      *(dp+of)=*(ap+of)^*(bp+of); // do the xor
173      ++of;
174    }
175    if(old->size!=diff->size){ // do we have to fill up ?
176      unsigned char n=0;
177      if(old->size<diff->size){
178        while(of<dest_length){
179          *(dp+of)=n^*(bp+of);
180          of++;
181        }
182      } else{
183        while(of<dest_length){
184          *(dp+of)=*(ap+of)^n;
185          of++;
186        }
187      }
188    }
189    // should be finished now
190    // FIXME: is it true or false now? (struct has changed, producing warnings)
191    GameState *r = new GameState;
192    r->id = diff->id;
193    r->size = dest_length;
194    r->base_id = old->id;
195    r->diffed = false;
196    r->data = dp;
197    return r;
198  }
199
200  //##### ADDED FOR TESTING PURPOSE #####
201  GameState* GameStateClient::testDecompress( GameStateCompressed* gc ) {
202    return decompress( gc );
203  }
204 
205  GameState* GameStateClient::testUndiff( GameState* g_old, GameState* g_diffed ) {
206    return undiff( g_old, g_diffed );
207  }
208  //##### ADDED FOR TESTING PURPOSE #####
209
210  GameState *GameStateClient::decompress(GameStateCompressed *a) {
211    //COUT(4) << "GameStateClient: uncompressing gamestate. id: " << a->id << ", baseid: " << a->base_id << ", normsize: " << a->normsize << ", compsize: " << a->compsize << std::endl;
212    int normsize = a->normsize;
213    int compsize = a->compsize;
214    int bufsize;
215    if(normsize < compsize)
216      bufsize = compsize;
217    else
218      bufsize = normsize;
219//     unsigned char* dest = (unsigned char*)malloc( bufsize );
220    unsigned char *dest = new unsigned char[bufsize];
221    int retval;
222    uLongf length=normsize;
223    //std::cout << "gamestateclient" << std::endl;
224    //std::cout << "normsize " << a.normsize << " compsize " << a.compsize << " " << bufsize << std::endl;
225    retval = uncompress( dest, &length, a->data, (uLong)compsize );
226    //std::cout << "length " << length << std::endl;
227    switch ( retval ) {
228      case Z_OK: COUT(4) << "successfully decompressed" << std::endl; break;
229      case Z_MEM_ERROR: COUT(1) << "not enough memory available" << std::endl; return NULL;
230      case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer" << std::endl; return NULL;
231      case Z_DATA_ERROR: COUT(2) << "data corrupted (zlib)" << std::endl; return NULL;
232    }
233
234    GameState *gamestate = new GameState;
235    gamestate->id = a->id;
236    gamestate->size = normsize;
237    gamestate->data = dest;
238    gamestate->base_id = a->base_id;
239    gamestate->diffed = a->diffed;
240
241    delete[] a->data; //delete compressed data
242    delete a; //we do not need the old (struct) gamestate anymore
243
244    return gamestate;
245  }
246
247  GameState *GameStateClient::decode(GameState *old, GameStateCompressed *diff) {
248    COUT(4) << "using diffed gamestate" << std::endl;
249    GameState *t = decode(diff);
250    return undiff(old, t);
251//     return t;
252  }
253
254  GameState *GameStateClient::decode(GameStateCompressed *x) {
255    GameState *t = decompress(x);
256    /*GameState *t = new GameState;
257    t->base_id = x->base_id;
258    t->id = x->id;
259    t->diffed = x->diffed;
260    t->data = x->data;
261    t->size = x->normsize;*/
262    return t;
263  }
264 
265  void GameStateClient::cleanup(){
266    std::map<int, GameState*>::iterator temp, it = gameStateMap.begin();
267    while(it!=gameStateMap.end()){
268      if(it->first>=last_diff_)
269        break;
270      // otherwise delete that stuff
271      delete[] (*it).second->data;
272      delete (*it).second;
273      temp=it++;
274      gameStateMap.erase(temp);
275    }
276  }
277
278  void GameStateClient::printGameStateMap(){
279    std::map<int, GameState*>::iterator it;
280    COUT(4) << "gamestates: ";
281    for(it=gameStateMap.begin(); it!=gameStateMap.end(); it++){
282      COUT(4) << it->first << ":" << it->second << "|";
283    }
284    COUT(4) << std::endl;
285   
286  }
287 
288}
Note: See TracBrowser for help on using the repository browser.