Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1011 was 1011, checked in by dumenim, 16 years ago

print gamestates on cout(4)

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