Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

blub

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