Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/FICN/src/network/GameStateManager.cc @ 663

Last change on this file since 663 was 656, checked in by scheusso, 17 years ago

some errors corrected in gamestatehandling

File size: 7.3 KB
RevLine 
[514]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
[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#include "GameStateManager.h"
40
41namespace network {
42
[436]43GameStateManager::GameStateManager(ClientInformation *head)
[247]44{
[413]45  id=0;
[436]46  head_=head;
[247]47}
48
49GameStateManager::~GameStateManager()
50{
51}
52
[413]53void GameStateManager::update(){
[422]54  reference = getSnapshot(id);
[436]55  gameStateMap.insert(std::pair<int, GameState*>(id, reference));
56  gameStateUsed[id]=0;
[422]57  ++id;
[413]58  return;
59}
60
61GameStateCompressed GameStateManager::popGameState(int clientID){
[436]62  int gID = head_->findClient(clientID)->getGamestateID();
[624]63  std::cout << "popgamestate: sending gstate id: " << id << "diffed from: " << gID << std::endl;
[436]64  if(gID!=GAMESTATEID_INITIAL){
65    GameState *client = gameStateMap[gID];
66    GameState *server = reference;
[624]67    //head_->findClient(clientID)->setGamestateID(id);
[436]68    return encode(client, server);
[620]69  } else {
70    GameState *server = reference;
[624]71    //head_->findClient(clientID)->setGamestateID(id);
[620]72    return encode(server);
73    // return an undiffed gamestate and set appropriate flags
[436]74  }
[413]75}
76
77
78
[332]79/**
[514]80 * This function goes through the whole list of synchronisables and
[332]81 * saves all the synchronisables to a flat "list".
82 * @return struct of type gamestate containing the size of the whole gamestate and a pointer linking to the flat list
83 */
[422]84GameState *GameStateManager::getSnapshot(int id)
[332]85{
86  //the size of the gamestate
87  int totalsize=0;
[590]88  int memsize=1000;
[332]89  //the size of one specific synchronisable
90  int tempsize=0;
91  // get the start of the Synchronisable list
92  orxonox::Iterator<Synchronisable> it;
93  // struct for return value of Synchronisable::getData()
94  syncData sync;
[514]95
[422]96  GameState *retval=new GameState; //return value
[568]97  retval->id=id++;
[624]98  std::cout << "producing gamestate with id: " << retval->id << std::endl;
[332]99  // reserve a little memory and increase it later on
[599]100  //COUT(2) << "mallocing" << std::endl;
[590]101  retval->data = (unsigned char*)malloc(memsize);
[599]102  //COUT(2) << "malloced" << std::endl;
[514]103
[332]104  // offset of memory functions
105  int offset=0;
106  // go through all Synchronisables
107  for(it = orxonox::ObjectList<Synchronisable>::start(); it != 0; ++it){
[620]108    //std::cout << "gamestatemanager: in for loop" << std::endl;
[332]109    //get size of the synchronisable
110    tempsize=it->getSize();
[632]111    //std::cout << "size of temp gamestate: " << tempsize << std::endl;
[569]112    //COUT(2) << "size of synchronisable: " << tempsize << std::endl;
[332]113    // add place for data and 3 ints (length,classid,objectid)
114    totalsize+=tempsize+3*sizeof(int);
[632]115    //std::cout << "totalsize: " << totalsize << std::endl;
[332]116    // allocate additional space
[590]117    if(totalsize+tempsize>memsize){
[630]118      if(tempsize<1000){
119        retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
120        memsize+=1000;
121      } else {
122        retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
123        memsize+=tempsize+1000;
124      }
[590]125    }
[514]126
[332]127    // run Synchronisable::getData with offset and additional place for 3 ints in between (for ids and length)
[656]128    sync=it->getData((retval->data)+offset+3*sizeof(int));
[422]129    *(retval->data+offset)=sync.length;
130    *(retval->data+offset+sizeof(int))=sync.objectID;
131    *(retval->data+offset+2*sizeof(int))=sync.classID;
[332]132    // increase data pointer
133    offset+=tempsize+3*sizeof(int);
134  }
[422]135  retval->size=totalsize;
[413]136  return retval;
[247]137}
138
139
[332]140
[413]141GameStateCompressed GameStateManager::encode(GameState *a, GameState *b){
[620]142  //GameState r = diff(a,b);
143  //r.diffed = true;
144  GameState r = *b;
145  r.diffed = false;
[436]146  return compress_(&r);
[385]147}
[332]148
[436]149GameStateCompressed GameStateManager::encode(GameState *a){
150  a->diffed=false;
151  return compress_(a);
152}
[332]153
[413]154GameState GameStateManager::diff(GameState *a, GameState *b){
155  unsigned char *ap = a->data, *bp = b->data;
[385]156  int of=0; // pointers offset
157  int dest_length=0;
[413]158  if(a->size>=b->size)
159    dest_length=a->size;
[385]160  else
[413]161    dest_length=b->size;
[385]162  unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));
[413]163  while(of<a->size && of<b->size){
[385]164    *(dp+of)=*(ap+of)^*(bp+of); // do the xor
165    ++of;
166  }
[413]167  if(a->size!=b->size){ // do we have to fill up ?
[385]168    unsigned char n=0;
[413]169    if(a->size<b->size){
[385]170      while(of<dest_length){
171        *(dp+of)=n^*(bp+of);
172        of++;
173      }
174    } else{
175      while(of<dest_length){
176        *(dp+of)=*(ap+of)^n;
177        of++;
178      }
179    }
180  }
181  // should be finished now
[413]182  GameState r = {b->id, dest_length, dp};
[385]183  return r;
184}
[332]185
[436]186GameStateCompressed GameStateManager::compress_(GameState *a) {
[620]187  //COUT(2) << "compressing gamestate" << std::endl;
[436]188  int size = a->size;
189  uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;
[407]190  unsigned char* dest = (unsigned char*)malloc( buffer );
191  int retval;
[632]192  //std::cout << "before ziped " << buffer << std::endl;
[514]193  retval = compress( dest, &buffer, a->data, (uLong)size );
[632]194  //std::cout << "after ziped " << buffer << std::endl;
[514]195
[407]196  switch ( retval ) {
[413]197  case Z_OK: std::cout << "successfully compressed" << std::endl; break;
198  case Z_MEM_ERROR: std::cout << "not enough memory available" << std::endl; break;
199  case Z_BUF_ERROR: std::cout << "not enough memory available in the buffer" << std::endl; break;
[620]200  case Z_DATA_ERROR: std::cout << "decompress: data corrupted" << std::endl; break;
[407]201  }
[514]202
[413]203  GameStateCompressed compressedGamestate;
[407]204  compressedGamestate.compsize = buffer;
[632]205  //std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl;
[407]206  compressedGamestate.normsize = size;
[632]207  //std::cout << "compressedGamestate.normsize = size; " << size << std::endl;
[624]208  compressedGamestate.id = a->id;
[407]209  compressedGamestate.data = dest;
[436]210  compressedGamestate.diffed = a->diffed;
[514]211
[407]212  return compressedGamestate;
[385]213}
214
[422]215void GameStateManager::ackGameState(int clientID, int gamestateID){
[436]216  ClientInformation *temp = head_->findClient(clientID);
217  int curid = temp->getID();
218  // decrease usage of gamestate and save it
219  deleteUnusedGameState(curid);
220  //increase gamestateused
221  ++gameStateUsed.find(gamestateID)->second;
222  temp->setGamestateID(gamestateID);
223  /*
[422]224  GameState *old = clientGameState[clientID];
225  deleteUnusedGameState(old);
[436]226  clientGameState[clientID]=idGameState[gamestateID];*/
[422]227}
[385]228
[436]229bool GameStateManager::deleteUnusedGameState(int gamestateID){
230  int used = --(gameStateUsed.find(gamestateID)->second);
231  if(id-gamestateID>KEEP_GAMESTATES && used==0){
232    // delete gamestate
233    delete gameStateMap.find(gamestateID)->second;
234    gameStateMap.erase(gamestateID);
235    return true;
[422]236  }
[436]237  return false;
[422]238}
[413]239
[385]240}
241
242
Note: See TracBrowser for help on using the repository browser.