Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

gamestatehandling, error correction

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