Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1009 was 1008, checked in by dumenim, 18 years ago

changed some comments and catched some return values and maybe some stuff we have to unchange

File size: 10.5 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 
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++);
[1007]89      }else  //as soon as we got a used gamestate break here because we could use newer gamestates in future
90        break;
[1005]91    }
92  }
[413]93
[894]94  GameStateCompressed *GameStateManager::popGameState(int clientID) {
[1008]95    //why are we searching the same client's gamestate id as we searched in
96    //Server::sendGameState?
[777]97    int gID = head_->findClient(clientID)->getGamestateID();
[1008]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){
[777]102      GameState *client = gameStateMap[gID];
103      GameState *server = reference;
104      //head_->findClient(clientID)->setGamestateID(id);
[894]105      return encode(client, server);
[777]106    } else {
107      GameState *server = reference;
108      //head_->findClient(clientID)->setGamestateID(id);
[894]109      return encode(server);
[777]110      // return an undiffed gamestate and set appropriate flags
111    }
112  }
[413]113
[777]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  {
[1008]121    //std::cout << "begin getSnapshot" << std::endl;
[777]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;
[413]131
[777]132    GameState *retval=new GameState; //return value
133    retval->id=id++;
[1008]134    COUT(4) << "G.ST.Man: producing gamestate with id: " << retval->id << std::endl;
[777]135    // reserve a little memory and increase it later on
[1008]136    COUT(5) << "G.ST.Man: mallocing: " << memsize << std::endl;
[777]137    retval->data = (unsigned char*)malloc(memsize);
[1008]138    COUT(5) << "G.ST.Man: malloced: " << memsize << std::endl;
[514]139
[777]140    // offset of memory functions
141    int offset=0;
142    // go through all Synchronisables
[871]143    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
[1008]144      //std::cout << "begin inner loop" << std::endl;
[777]145      //std::cout << "gamestatemanager: in for loop" << std::endl;
146      //get size of the synchronisable
147      tempsize=it->getSize();
[1008]148      //COUT(5) << "size of temp gamestate: " << tempsize << std::endl;
[777]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;
[1008]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;
[777]155      // allocate additional space
[1008]156      if((totalsize+tempsize) > memsize){
157        COUT(5) << "G.St.Man: need additional memory" << std::endl;
158        if(tempsize < 1000){
[777]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        }
[1008]165        COUT(5) << "G.St.Man: additional space allocation finished" << std::endl;
[777]166      }
[514]167
[777]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));
[986]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;
[777]176      // increase data pointer
177      offset+=tempsize+3*sizeof(int);
[1008]178      //std::cout << "end inner loop" << std::endl;
[590]179    }
[777]180    retval->size=totalsize;
[984]181    //#### bugfix
182    retval->diffed = false;
[1008]183    //std::cout << "end snapShot" << std::endl;
184    COUT(5) << "G.ST.Man: Gamestate size: " << totalsize << std::endl;
[777]185    return retval;
186  }
[514]187
[984]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
[891]198  GameStateCompressed *GameStateManager::encode(GameState *a, GameState *b) {
[1008]199    COUT(5) << "G.St.Man: this will be a DIFFED gamestate" << std::endl;
[777]200    //GameState r = diff(a,b);
201    //r.diffed = true;
[891]202    GameState *r = b;
203    r->diffed = false;
204    return compress_(r);
[332]205  }
[247]206
[891]207  GameStateCompressed *GameStateManager::encode(GameState *a) {
[1008]208    COUT(5) << "G.St.Man: this will be a not diffed gamestate" << std::endl;
[777]209    a->diffed=false;
210    return compress_(a);
211  }
[247]212
[891]213  GameState *GameStateManager::diff(GameState *a, GameState *b) {
[777]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        }
[385]238      }
239    }
[891]240   
241    GameState *r = new GameState;
242    r->id = b->id;
243    r->size = dest_length;
244    r->diffed = true;
[986]245    r->base_id = a->id;
[891]246    r->data = dp;
[777]247    return r;
[385]248  }
[332]249
[891]250  GameStateCompressed *GameStateManager::compress_(GameState *a) {
[1008]251    COUT(5) << "G.St.Man: compressing gamestate" << std::endl;
[777]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;
[514]259
[777]260    switch ( retval ) {
[1008]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; 
[891]263      return NULL;
[1008]264      case Z_BUF_ERROR: COUT(2) << "G.St.Man: compress: not enough memory available in the buffer in gamestate.compress" << std::endl;
[891]265      return NULL;
[1008]266      case Z_DATA_ERROR: COUT(2) << "G.St.Man: compress: data corrupted in gamestate.compress" << std::endl;
[891]267      return NULL;
[777]268    }
[514]269
[891]270    GameStateCompressed *compressedGamestate = new GameStateCompressed;
271    compressedGamestate->compsize = buffer;
[889]272//     std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl;
[891]273    compressedGamestate->normsize = size;
[889]274//     std::cout << "compressedGamestate.normsize = size; " << size << std::endl;
[891]275    compressedGamestate->id = a->id;
276    compressedGamestate->data = dest;
277    compressedGamestate->diffed = a->diffed;
[986]278    compressedGamestate->base_id = a->base_id;
[1008]279    COUT(5) << "G.St.Man: saved compressed data in GameStateCompressed" << std::endl;
[777]280    return compressedGamestate;
281  }
[385]282
[777]283  void GameStateManager::ackGameState(int clientID, int gamestateID) {
284    ClientInformation *temp = head_->findClient(clientID);
285    int curid = temp->getID();
286    // decrease usage of gamestate and save it
287    deleteUnusedGameState(curid);
288    //increase gamestateused
289    ++gameStateUsed.find(gamestateID)->second;
290    temp->setGamestateID(gamestateID);
291    /*
292    GameState *old = clientGameState[clientID];
293    deleteUnusedGameState(old);
294    clientGameState[clientID]=idGameState[gamestateID];*/
295  }
[385]296
[777]297  bool GameStateManager::deleteUnusedGameState(int gamestateID) {
298    int used = --(gameStateUsed.find(gamestateID)->second);
299    if(id-gamestateID>KEEP_GAMESTATES && used==0){
300      // delete gamestate
301      delete gameStateMap.find(gamestateID)->second;
302      gameStateMap.erase(gamestateID);
303      return true;
304    }
305    return false;
[422]306  }
[413]307
[385]308}
Note: See TracBrowser for help on using the repository browser.