Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1062 was 1062, checked in by rgrieder, 16 years ago
  • changed header file inclusion order
File size: 8.1 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Oliver Scheuss, (C) 2007
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29//
30// C++ Implementation: GameStateManager
31//
32// Description:
33//
34//
35// Author:  Oliver Scheuss, (C) 2007
36//
37// Copyright: See COPYING file that comes with this distribution
38//
39//
40
41#include "GameStateManager.h"
42
43#include <utility>
44#include <iostream>
45#include <zlib.h>
46
47#include "core/CoreIncludes.h"
48#include "ClientInformation.h"
49#include "Synchronisable.h"
50
51namespace network
52{
53  GameStateManager::GameStateManager(ClientInformation *head) {
54    id=0;
55    head_=head;
56  }
57
58  GameStateManager::~GameStateManager() {
59  }
60
61  void GameStateManager::update(){
62    reference = getSnapshot(id);
63    gameStateMap.insert(std::pair<int, GameState*>(id, reference));
64    gameStateUsed[id]=0;
65    ++id;
66    return;
67  }
68
69  GameStateCompressed *GameStateManager::popGameState(int clientID) {
70    int gID = head_->findClient(clientID)->getGamestateID();
71    COUT(4) << "popgamestate: sending gstate id: " << id << "diffed from: " << gID << std::endl;
72    if(gID!=GAMESTATEID_INITIAL){
73      GameState *client = gameStateMap[gID];
74      GameState *server = reference;
75      //head_->findClient(clientID)->setGamestateID(id);
76      return encode(client, server);
77    } else {
78      GameState *server = reference;
79      //head_->findClient(clientID)->setGamestateID(id);
80      return encode(server);
81      // return an undiffed gamestate and set appropriate flags
82    }
83  }
84
85  /**
86  * This function goes through the whole list of synchronisables and
87  * saves all the synchronisables to a flat "list".
88  * @return struct of type gamestate containing the size of the whole gamestate and a pointer linking to the flat list
89  */
90  GameState *GameStateManager::getSnapshot(int id)
91  {
92    //the size of the gamestate
93    int totalsize=0;
94    int memsize=1000;
95    //the size of one specific synchronisable
96    int tempsize=0;
97    // get the start of the Synchronisable list
98    orxonox::Iterator<Synchronisable> it;
99    // struct for return value of Synchronisable::getData()
100    syncData sync;
101
102    GameState *retval=new GameState; //return value
103    retval->id=id++;
104    COUT(4) << "producing gamestate with id: " << retval->id << std::endl;
105    // reserve a little memory and increase it later on
106    COUT(5) << "mallocing" << std::endl;
107    retval->data = (unsigned char*)malloc(memsize);
108    COUT(5) << "malloced" << std::endl;
109
110    // offset of memory functions
111    int offset=0;
112    // go through all Synchronisables
113    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
114      //std::cout << "gamestatemanager: in for loop" << std::endl;
115      //get size of the synchronisable
116      tempsize=it->getSize();
117//       COUT(5) << "size of temp gamestate: " << tempsize << std::endl;
118      //COUT(2) << "size of synchronisable: " << tempsize << std::endl;
119      // add place for data and 3 ints (length,classid,objectid)
120      totalsize+=tempsize+3*sizeof(int);
121      //std::cout << "totalsize: " << totalsize << std::endl;
122      // allocate additional space
123      if(totalsize+tempsize>memsize){
124        if(tempsize<1000){
125          retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
126          memsize+=1000;
127        } else {
128          retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);
129          memsize+=tempsize+1000;
130        }
131      }
132
133      // run Synchronisable::getData with offset and additional place for 3 ints in between (for ids and length)
134      sync=it->getData((retval->data)+offset+3*sizeof(int));
135      *(retval->data+offset)=sync.length;
136      *(retval->data+offset+sizeof(int))=sync.objectID;
137      *(retval->data+offset+2*sizeof(int))=sync.classID;
138      // increase data pointer
139      offset+=tempsize+3*sizeof(int);
140    }
141    COUT(5) << "Gamestate size: " << totalsize << std::endl;
142    retval->size=totalsize;
143    return retval;
144  }
145
146  GameStateCompressed *GameStateManager::encode(GameState *a, GameState *b) {
147    //GameState r = diff(a,b);
148    //r.diffed = true;
149    GameState *r = b;
150    r->diffed = false;
151    return compress_(r);
152  }
153
154  GameStateCompressed *GameStateManager::encode(GameState *a) {
155    a->diffed=false;
156    return compress_(a);
157  }
158
159  GameState *GameStateManager::diff(GameState *a, GameState *b) {
160    unsigned char *ap = a->data, *bp = b->data;
161    int of=0; // pointers offset
162    int dest_length=0;
163    if(a->size>=b->size)
164      dest_length=a->size;
165    else
166      dest_length=b->size;
167    unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));
168    while(of<a->size && of<b->size){
169      *(dp+of)=*(ap+of)^*(bp+of); // do the xor
170      ++of;
171    }
172    if(a->size!=b->size){ // do we have to fill up ?
173      unsigned char n=0;
174      if(a->size<b->size){
175        while(of<dest_length){
176          *(dp+of)=n^*(bp+of);
177          of++;
178        }
179      } else{
180        while(of<dest_length){
181          *(dp+of)=*(ap+of)^n;
182          of++;
183        }
184      }
185    }
186
187    GameState *r = new GameState;
188    r->id = b->id;
189    r->size = dest_length;
190    r->diffed = true;
191    r->data = dp;
192    return r;
193  }
194
195  GameStateCompressed *GameStateManager::compress_(GameState *a) {
196    COUT(5) << "compressing gamestate" << std::endl;
197    int size = a->size;
198    uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;
199    unsigned char* dest = (unsigned char*)malloc( buffer );
200    int retval;
201    //std::cout << "before ziped " << buffer << std::endl;
202    retval = compress( dest, &buffer, a->data, (uLong)size );
203    //std::cout << "after ziped " << buffer << std::endl;
204
205    switch ( retval ) {
206      case Z_OK: COUT(5) << "successfully compressed" << std::endl; break;
207      case Z_MEM_ERROR: COUT(1) << "not enough memory available in gamestate.compress" << std::endl;
208      return NULL;
209      case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer in gamestate.compress" << std::endl;
210      return NULL;
211      case Z_DATA_ERROR: COUT(2) << "decompress: data corrupted in gamestate.compress" << std::endl;
212      return NULL;
213    }
214
215    GameStateCompressed *compressedGamestate = new GameStateCompressed;
216    compressedGamestate->compsize = buffer;
217//     std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl;
218    compressedGamestate->normsize = size;
219//     std::cout << "compressedGamestate.normsize = size; " << size << std::endl;
220    compressedGamestate->id = a->id;
221    compressedGamestate->data = dest;
222    compressedGamestate->diffed = a->diffed;
223
224    return compressedGamestate;
225  }
226
227  void GameStateManager::ackGameState(int clientID, int gamestateID) {
228    ClientInformation *temp = head_->findClient(clientID);
229    int curid = temp->getID();
230    // decrease usage of gamestate and save it
231    deleteUnusedGameState(curid);
232    //increase gamestateused
233    ++gameStateUsed.find(gamestateID)->second;
234    temp->setGamestateID(gamestateID);
235    /*
236    GameState *old = clientGameState[clientID];
237    deleteUnusedGameState(old);
238    clientGameState[clientID]=idGameState[gamestateID];*/
239  }
240
241  bool GameStateManager::deleteUnusedGameState(int gamestateID) {
242    int used = --(gameStateUsed.find(gamestateID)->second);
243    if(id-gamestateID>KEEP_GAMESTATES && used==0){
244      // delete gamestate
245      delete gameStateMap.find(gamestateID)->second;
246      gameStateMap.erase(gamestateID);
247      return true;
248    }
249    return false;
250  }
251
252}
Note: See TracBrowser for help on using the repository browser.