Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/network/GameStateManager.cc @ 1031

Last change on this file since 1031 was 1021, checked in by bknecht, 16 years ago

merged back that script-branch

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