Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/network/GameStateManager.cc @ 1005

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

enhanced memory management in gamestatemanager and gamestateclient

File size: 9.3 KB
Line 
1/*
2*   ORXONOX - the hottest 3D action shooter ever to exist
3*
4*
5*   License notice:
6*
7*   This program is free software; you can redistribute it and/or
8*   modify it under the terms of the GNU General Public License
9*   as published by the Free Software Foundation; either version 2
10*   of the License, or (at your option) any later version.
11*
12*   This program is distributed in the hope that it will be useful,
13*   but WITHOUT ANY WARRANTY; without even the implied warranty of
14*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*   GNU General Public License for more details.
16*
17*   You should have received a copy of the GNU General Public License
18*   along with this program; if not, write to the Free Software
19*   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20*
21*   Author:
22*      Oliver Scheuss, (C) 2007
23*   Co-authors:
24*      ...
25*
26*/
27
28//
29// C++ Implementation: GameStateManager
30//
31// Description:
32//
33//
34// Author:  Oliver Scheuss, (C) 2007
35//
36// Copyright: See COPYING file that comes with this distribution
37//
38//
39
40#include <utility>
41#include <iostream>
42#include <zlib.h>
43
44#include "core/CoreIncludes.h"
45
46#include "ClientInformation.h"
47#include "Synchronisable.h"
48#include "GameStateManager.h"
49
50namespace network
51{
52  GameStateManager::GameStateManager(ClientInformation *head) {
53    id=0;
54    head_=head;
55  }
56
57  GameStateManager::~GameStateManager() {
58  }
59
60  void GameStateManager::update(){
61    reference = getSnapshot(id);
62    gameStateMap.insert(std::pair<int, GameState*>(id, reference));
63    gameStateUsed[id]=0;
64    ++id;
65    return;
66  }
67 
68  void GameStateManager::cleanup(){
69    /*unsigned int min_id=-1;
70    int temp_id=0;
71    ClientInformation *temp = head_;
72    while(temp){
73      if(temp->head)
74        continue;
75      temp_id=temp->getID();
76      if(temp_id<min_id)
77        min_id=temp_id;
78      temp=temp->next();
79    }*/ // probably not very efficient
80   
81    std::map<int,int>::iterator it = gameStateUsed.begin();
82    while(it!=gameStateUsed.end()){
83      if( (*it).second <= 0 ){
84        free(gameStateMap[(*it).first]->data);
85        delete gameStateMap[(*it).first];
86        gameStateMap.erase((*it).first);
87        gameStateUsed.erase(it++);
88      }else
89        it++;
90    }
91  }
92
93  GameStateCompressed *GameStateManager::popGameState(int clientID) {
94    int gID = head_->findClient(clientID)->getGamestateID();
95    COUT(4) << "popgamestate: sending gstate id: " << id << "diffed from: " << gID << std::endl;
96    if(gID!=GAMESTATEID_INITIAL){
97      GameState *client = gameStateMap[gID];
98      GameState *server = reference;
99      //head_->findClient(clientID)->setGamestateID(id);
100      return encode(client, server);
101    } else {
102      GameState *server = reference;
103      //head_->findClient(clientID)->setGamestateID(id);
104      return encode(server);
105      // return an undiffed gamestate and set appropriate flags
106    }
107  }
108
109  /**
110  * This function goes through the whole list of synchronisables and
111  * saves all the synchronisables to a flat "list".
112  * @return struct of type gamestate containing the size of the whole gamestate and a pointer linking to the flat list
113  */
114  GameState *GameStateManager::getSnapshot(int id)
115  {
116    //the size of the gamestate
117    int totalsize=0;
118    int memsize=1000;
119    //the size of one specific synchronisable
120    int tempsize=0;
121    // get the start of the Synchronisable list
122    orxonox::Iterator<Synchronisable> it;
123    // struct for return value of Synchronisable::getData()
124    syncData sync;
125
126    GameState *retval=new GameState; //return value
127    retval->id=id++;
128    COUT(4) << "producing gamestate with id: " << retval->id << std::endl;
129    // reserve a little memory and increase it later on
130    COUT(5) << "mallocing" << std::endl;
131    retval->data = (unsigned char*)malloc(memsize);
132    COUT(5) << "malloced" << std::endl;
133
134    // offset of memory functions
135    int offset=0;
136    // go through all Synchronisables
137    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
138      //std::cout << "gamestatemanager: in for loop" << std::endl;
139      //get size of the synchronisable
140      tempsize=it->getSize();
141//       COUT(5) << "size of temp gamestate: " << tempsize << std::endl;
142      //COUT(2) << "size of synchronisable: " << tempsize << std::endl;
143      // add place for data and 3 ints (length,classid,objectid)
144      totalsize+=tempsize+3*sizeof(int);
145      //std::cout << "totalsize: " << totalsize << std::endl;
146      // allocate additional space
147      if(totalsize+tempsize>memsize){
148        if(tempsize<1000){
149          retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
150          memsize+=1000;
151        } else {
152          retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
153          memsize+=tempsize+1000;
154        }
155      }
156
157      // run Synchronisable::getData with offset and additional place for 3 ints in between (for ids and length)
158      sync=it->getData((retval->data)+offset+3*sizeof(int));
159      memcpy(retval->data+offset, (void *)&sync.length, sizeof(int));
160      //*(retval->data+offset)=sync.length;
161      memcpy(retval->data+offset+sizeof(int), (void *)&sync.objectID, sizeof(int));
162      //*(retval->data+offset+sizeof(int))=sync.objectID;
163      memcpy(retval->data+offset+2*sizeof(int), (void *)&sync.classID, sizeof(int));
164      //*(retval->data+offset+2*sizeof(int))=sync.classID;
165      // increase data pointer
166      offset+=tempsize+3*sizeof(int);
167    }
168    COUT(5) << "Gamestate size: " << totalsize << std::endl;
169    retval->size=totalsize;
170    //#### bugfix
171    retval->diffed = false;
172    return retval;
173  }
174
175  //##### ADDED FOR TESTING PURPOSE #####
176  GameStateCompressed* GameStateManager::testCompress( GameState* g ) {
177    return compress_( g );
178  }
179
180  GameState* GameStateManager::testDiff( GameState* a, GameState* b ) {
181    return diff( a, b );
182  }
183  //##### END TESTING PURPOSE #####
184
185  GameStateCompressed *GameStateManager::encode(GameState *a, GameState *b) {
186    //GameState r = diff(a,b);
187    //r.diffed = true;
188    GameState *r = b;
189    r->diffed = false;
190    return compress_(r);
191  }
192
193  GameStateCompressed *GameStateManager::encode(GameState *a) {
194    a->diffed=false;
195    return compress_(a);
196  }
197
198  GameState *GameStateManager::diff(GameState *a, GameState *b) {
199    unsigned char *ap = a->data, *bp = b->data;
200    int of=0; // pointers offset
201    int dest_length=0;
202    if(a->size>=b->size)
203      dest_length=a->size;
204    else
205      dest_length=b->size;
206    unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));
207    while(of<a->size && of<b->size){
208      *(dp+of)=*(ap+of)^*(bp+of); // do the xor
209      ++of;
210    }
211    if(a->size!=b->size){ // do we have to fill up ?
212      unsigned char n=0;
213      if(a->size<b->size){
214        while(of<dest_length){
215          *(dp+of)=n^*(bp+of);
216          of++;
217        }
218      } else{
219        while(of<dest_length){
220          *(dp+of)=*(ap+of)^n;
221          of++;
222        }
223      }
224    }
225   
226    GameState *r = new GameState;
227    r->id = b->id;
228    r->size = dest_length;
229    r->diffed = true;
230    r->base_id = a->id;
231    r->data = dp;
232    return r;
233  }
234
235  GameStateCompressed *GameStateManager::compress_(GameState *a) {
236    COUT(5) << "compressing gamestate" << std::endl;
237    int size = a->size;
238    uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;
239    unsigned char* dest = (unsigned char*)malloc( buffer );
240    int retval;
241    //std::cout << "before ziped " << buffer << std::endl;
242    retval = compress( dest, &buffer, a->data, (uLong)size );
243    //std::cout << "after ziped " << buffer << std::endl;
244
245    switch ( retval ) {
246      case Z_OK: COUT(5) << "successfully compressed" << std::endl; break;
247      case Z_MEM_ERROR: COUT(1) << "not enough memory available in gamestate.compress" << std::endl; 
248      return NULL;
249      case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer in gamestate.compress" << std::endl;
250      return NULL;
251      case Z_DATA_ERROR: COUT(2) << "decompress: data corrupted in gamestate.compress" << std::endl;
252      return NULL;
253    }
254
255    GameStateCompressed *compressedGamestate = new GameStateCompressed;
256    compressedGamestate->compsize = buffer;
257//     std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl;
258    compressedGamestate->normsize = size;
259//     std::cout << "compressedGamestate.normsize = size; " << size << std::endl;
260    compressedGamestate->id = a->id;
261    compressedGamestate->data = dest;
262    compressedGamestate->diffed = a->diffed;
263    compressedGamestate->base_id = a->base_id;
264
265    return compressedGamestate;
266  }
267
268  void GameStateManager::ackGameState(int clientID, int gamestateID) {
269    ClientInformation *temp = head_->findClient(clientID);
270    int curid = temp->getID();
271    // decrease usage of gamestate and save it
272    deleteUnusedGameState(curid);
273    //increase gamestateused
274    ++gameStateUsed.find(gamestateID)->second;
275    temp->setGamestateID(gamestateID);
276    /*
277    GameState *old = clientGameState[clientID];
278    deleteUnusedGameState(old);
279    clientGameState[clientID]=idGameState[gamestateID];*/
280  }
281
282  bool GameStateManager::deleteUnusedGameState(int gamestateID) {
283    int used = --(gameStateUsed.find(gamestateID)->second);
284    if(id-gamestateID>KEEP_GAMESTATES && used==0){
285      // delete gamestate
286      delete gameStateMap.find(gamestateID)->second;
287      gameStateMap.erase(gamestateID);
288      return true;
289    }
290    return false;
291  }
292
293}
Note: See TracBrowser for help on using the repository browser.