Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network3/src/network/GameStateManager.cc @ 1173

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

changed some things

File size: 11.0 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, (C) 2007
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29//
30// C++ Implementation: GameStateManager
31//
32// Description:
33//
34//
35// Author:  Oliver Scheuss, (C) 2007
36//
37// Copyright: See COPYING file that comes with this distribution
38//
39//
40
41#include "GameStateManager.h"
42
43#include <utility>
44#include <iostream>
45#include <zlib.h>
46
47#include "core/CoreIncludes.h"
48#include "ClientInformation.h"
49#include "Synchronisable.h"
50
51namespace network
52{
53  GameStateManager::GameStateManager(ClientInformation *head) {
54    id=0;
55    head_=head;
56  }
57
58  GameStateManager::~GameStateManager() {
59  }
60
61  void GameStateManager::update(){
62    cleanup();
63    reference = getSnapshot(id);
64    gameStateMap.insert(std::pair<int, GameState*>(id, reference));
65    gameStateUsed[id]=0;
66    ++id;
67    return;
68  }
69 
70 
71  /**
72   * this function is used to keep the memory usage low
73   * it tries to delete all the unused gamestates
74   *
75   *
76   */
77  void GameStateManager::cleanup(){
78    std::map<int,int>::iterator it = gameStateUsed.begin();
79    while(it!=gameStateUsed.end()){
80      if( (*it).second <= 0 ){
81        free(gameStateMap[(*it).first]->data);
82        delete gameStateMap[(*it).first];
83        gameStateMap.erase((*it).first);
84        gameStateUsed.erase(it++);
85      }else  //as soon as we got a used gamestate break here because we could use newer gamestates in future
86        break;
87    }
88  }
89
90  GameStateCompressed *GameStateManager::popGameState(int clientID) {
91    //why are we searching the same client's gamestate id as we searched in
92    //Server::sendGameState?
93    int gID = head_->findClient(clientID)->getGamestateID();
94    COUT(4) << "G.St.Man: popgamestate: sending gstate_id: " << id << " diffed from: " << gID << " (not diffed yet)" << std::endl;
95   
96    //chose wheather the next gamestate is the first or not
97    if(gID != GAMESTATEID_INITIAL){
98      GameState *client = gameStateMap[gID];
99      GameState *server = reference;
100      //head_->findClient(clientID)->setGamestateID(id);
101      return encode(client, server);
102    } else {
103      GameState *server = reference;
104      //head_->findClient(clientID)->setGamestateID(id);
105      return encode(server);
106      // return an undiffed gamestate and set appropriate flags
107    }
108  }
109
110  /**
111  * This function goes through the whole list of synchronisables and
112  * saves all the synchronisables to a flat "list".
113  * @return struct of type gamestate containing the size of the whole gamestate and a pointer linking to the flat list
114  */
115  GameState *GameStateManager::getSnapshot(int id)
116  {
117    //std::cout << "begin getSnapshot" << std::endl;
118    //the size of the gamestate
119    int totalsize=0;
120    int memsize=1000;
121    //the size of one specific synchronisable
122    int tempsize=0;
123    // get the start of the Synchronisable list
124    orxonox::Iterator<Synchronisable> it;
125    // struct for return value of Synchronisable::getData()
126    syncData sync;
127
128    GameState *retval=new GameState; //return value
129    retval->id=id++;
130    COUT(4) << "G.ST.Man: producing gamestate with id: " << retval->id << std::endl;
131    // offset of memory functions
132    int offset=0, size=0;
133    // get total size of gamestate
134    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
135      size+=it->getSize();
136      size+=3*sizeof(int);
137    }
138    retval->data = (unsigned char*)malloc(size);
139    if(!retval->data){
140      COUT(2) << "GameStateManager: could not allocate memory" << std::endl;
141      return NULL;
142    }
143    memsize=size;
144    // go through all Synchronisables
145    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
146      //get size of the synchronisable
147      tempsize=it->getSize();
148      // add place for data and 3 ints (length,classid,objectid)
149      totalsize+=tempsize+3*sizeof(int);
150      // allocate additional space
151      if((totalsize+tempsize) > memsize){
152        COUT(5) << "G.St.Man: need additional memory" << std::endl;
153//         if(tempsize < 1000){
154//           retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
155//           memsize+=1000;
156//         } else {
157//           retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
158//           memsize+=tempsize+1000;
159//         }
160//         COUT(5) << "G.St.Man: additional space allocation finished" << std::endl;
161      }
162
163      // run Synchronisable::getData with offset and additional place for 3 ints in between (for ids and length)
164      sync=it->getData((retval->data)+offset+3*sizeof(int));
165      memcpy(retval->data+offset, (void *)&(sync.length), sizeof(int));
166      memcpy(retval->data+offset+sizeof(int), (void *)&(sync.objectID), sizeof(int));
167      memcpy(retval->data+offset+2*sizeof(int), (void *)&(sync.classID), sizeof(int));
168      // increase data pointer
169      offset+=tempsize+3*sizeof(int);
170    }
171    retval->size=totalsize;
172    //#### bugfix
173    retval->diffed = false;
174    //std::cout << "end snapShot" << std::endl;
175    COUT(5) << "G.ST.Man: Gamestate size: " << totalsize << std::endl;
176    COUT(5) << "G.ST.Man: 'estimated' Gamestate size: " << size << std::endl;
177    return retval;
178  }
179
180  //##### ADDED FOR TESTING PURPOSE #####
181  GameStateCompressed* GameStateManager::testCompress( GameState* g ) {
182    return compress_( g );
183  }
184
185  GameState* GameStateManager::testDiff( GameState* a, GameState* b ) {
186    return diff( a, b );
187  }
188  //##### END TESTING PURPOSE #####
189
190  GameStateCompressed *GameStateManager::encode(GameState *a, GameState *b) {
191    COUT(5) << "G.St.Man: this will be a DIFFED gamestate" << std::endl;
192    //GameState r = diff(a,b);
193    //r.diffed = true;
194    GameState *r = b;
195    r->diffed = false;
196    //return compress_(r);
197    GameStateCompressed *g = new GameStateCompressed;
198    g->base_id = b->base_id;
199    g->id = b->id;
200    g->diffed = b->diffed;
201    g->data = b->data;
202    g->normsize = b->size;
203    g->compsize = b->size;
204    return g;
205  }
206
207  GameStateCompressed *GameStateManager::encode(GameState *a) {
208    COUT(5) << "G.St.Man: this will be a not diffed gamestate" << std::endl;
209    a->diffed=false;
210    GameStateCompressed *g = new GameStateCompressed;
211    g->base_id = a->base_id;
212    g->id = a->id;
213    g->diffed = a->diffed;
214    g->data = a->data;
215    g->normsize = a->size;
216    g->compsize = a->size;
217    return g;
218  }
219
220  GameState *GameStateManager::diff(GameState *a, GameState *b) {
221    unsigned char *ap = a->data, *bp = b->data;
222    int of=0; // pointers offset
223    int dest_length=0;
224    if(a->size>=b->size)
225      dest_length=a->size;
226    else
227      dest_length=b->size;
228    unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));
229    while(of<a->size && of<b->size){
230      *(dp+of)=*(ap+of)^*(bp+of); // do the xor
231      ++of;
232    }
233    if(a->size!=b->size){ // do we have to fill up ?
234      unsigned char n=0;
235      if(a->size<b->size){
236        while(of<dest_length){
237          *(dp+of)=n^*(bp+of);
238          of++;
239        }
240      } else{
241        while(of<dest_length){
242          *(dp+of)=*(ap+of)^n;
243          of++;
244        }
245      }
246    }
247
248    GameState *r = new GameState;
249    r->id = b->id;
250    r->size = dest_length;
251    r->diffed = true;
252    r->base_id = a->id;
253    r->data = dp;
254    return r;
255  }
256
257  GameStateCompressed *GameStateManager::compress_(GameState *a) {
258    //COUT(4) << "G.St.Man: compressing gamestate" << std::endl;
259
260    //COUT(4) << "G.St.Man: a: id: " << a->id << " base_id: " << a->base_id << " size: " << a->size << " diffed: " << a->diffed << std::endl;
261    int size = a->size;
262
263    uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;
264    //COUT(4) << "size: " << size << ", buffer: " << buffer << std::endl;
265    unsigned char* dest = (unsigned char*)malloc( buffer );
266    //COUT(4) << "dest: " << dest << std::endl;
267    int retval;
268    //std::cout << "before ziped " << buffer << std::endl;
269    retval = compress( dest, &buffer, a->data, (uLong)size );
270    //COUT(4) << "bloablabla aft3er compress" << std::endl;
271    //std::cout << "after ziped " << buffer << std::endl;
272
273    switch ( retval ) {
274      case Z_OK: COUT(5) << "G.St.Man: compress: successfully compressed" << std::endl; break;
275      case Z_MEM_ERROR: COUT(1) << "G.St.Man: compress: not enough memory available in gamestate.compress" << std::endl; 
276      return NULL;
277      case Z_BUF_ERROR: COUT(2) << "G.St.Man: compress: not enough memory available in the buffer in gamestate.compress" << std::endl;
278      return NULL;
279      case Z_DATA_ERROR: COUT(2) << "G.St.Man: compress: data corrupted in gamestate.compress" << std::endl;
280      return NULL;
281    }
282
283    GameStateCompressed *compressedGamestate = new GameStateCompressed;
284    compressedGamestate->compsize = buffer;
285//     std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl;
286    compressedGamestate->normsize = size;
287//     std::cout << "compressedGamestate.normsize = size; " << size << std::endl;
288    compressedGamestate->id = a->id;
289    compressedGamestate->data = dest;
290    compressedGamestate->diffed = a->diffed;
291    compressedGamestate->base_id = a->base_id;
292    //COUT(5) << "G.St.Man: saved compressed data in GameStateCompressed:" << std::endl;
293    return compressedGamestate;
294  }
295
296  void GameStateManager::ackGameState(int clientID, int gamestateID) {
297    ClientInformation *temp = head_->findClient(clientID);
298    int curid = temp->getID();
299    // decrease usage of gamestate and save it
300    deleteUnusedGameState(curid);
301    //increase gamestateused
302    ++gameStateUsed.find(gamestateID)->second;
303    temp->setGamestateID(gamestateID);
304    /*
305    GameState *old = clientGameState[clientID];
306    deleteUnusedGameState(old);
307    clientGameState[clientID]=idGameState[gamestateID];*/
308  }
309
310  bool GameStateManager::deleteUnusedGameState(int gamestateID) {
311    int used = --(gameStateUsed.find(gamestateID)->second);
312    if(id-gamestateID>KEEP_GAMESTATES && used==0){
313      // delete gamestate
314      delete gameStateMap.find(gamestateID)->second;
315      gameStateMap.erase(gamestateID);
316      return true;
317    }
318    return false;
319  }
320
321}
Note: See TracBrowser for help on using the repository browser.