Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 984 was 984, checked in by dumenim, 16 years ago

some bugfix in GameStateManager.cc, CMakeLists now generates networktest executable, some test functions added

File size: 8.3 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
40#include <utility>
41#include <iostream>
42#include <zlib.h>
43
44#include "core/CoreIncludes.h"
45
46#include "ClientInformation.h"
47#include "Synchronisable.h"
48#include "GameStateManager.h"
49
50namespace network
51{
52  GameStateManager::GameStateManager(ClientInformation *head) {
53    id=0;
54    head_=head;
55  }
56
57  GameStateManager::~GameStateManager() {
58  }
59
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;
66  }
67
68  GameStateCompressed *GameStateManager::popGameState(int clientID) {
69    int gID = head_->findClient(clientID)->getGamestateID();
70    COUT(4) << "popgamestate: sending gstate id: " << id << "diffed from: " << gID << std::endl;
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  }
83
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;
100
101    GameState *retval=new GameState; //return value
102    retval->id=id++;
103    COUT(4) << "producing gamestate with id: " << retval->id << std::endl;
104    // reserve a little memory and increase it later on
105    COUT(5) << "mallocing" << std::endl;
106    retval->data = (unsigned char*)malloc(memsize);
107    COUT(5) << "malloced" << std::endl;
108
109    // offset of memory functions
110    int offset=0;
111    // go through all Synchronisables
112    for(it = orxonox::ObjectList<Synchronisable>::start(); it; ++it){
113      //std::cout << "gamestatemanager: in for loop" << std::endl;
114      //get size of the synchronisable
115      tempsize=it->getSize();
116//       COUT(5) << "size of temp gamestate: " << tempsize << std::endl;
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      }
131
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);
139    }
140    COUT(5) << "Gamestate size: " << totalsize << std::endl;
141    retval->size=totalsize;
142    //#### bugfix
143    retval->diffed = false;
144    return retval;
145  }
146
147  //##### ADDED FOR TESTING PURPOSE #####
148  GameStateCompressed* GameStateManager::testCompress( GameState* g ) {
149    return compress_( g );
150  }
151
152  GameState* GameStateManager::testDiff( GameState* a, GameState* b ) {
153    return diff( a, b );
154  }
155  //##### END TESTING PURPOSE #####
156
157  GameStateCompressed *GameStateManager::encode(GameState *a, GameState *b) {
158    //GameState r = diff(a,b);
159    //r.diffed = true;
160    GameState *r = b;
161    r->diffed = false;
162    return compress_(r);
163  }
164
165  GameStateCompressed *GameStateManager::encode(GameState *a) {
166    a->diffed=false;
167    return compress_(a);
168  }
169
170  GameState *GameStateManager::diff(GameState *a, GameState *b) {
171    unsigned char *ap = a->data, *bp = b->data;
172    int of=0; // pointers offset
173    int dest_length=0;
174    if(a->size>=b->size)
175      dest_length=a->size;
176    else
177      dest_length=b->size;
178    unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));
179    while(of<a->size && of<b->size){
180      *(dp+of)=*(ap+of)^*(bp+of); // do the xor
181      ++of;
182    }
183    if(a->size!=b->size){ // do we have to fill up ?
184      unsigned char n=0;
185      if(a->size<b->size){
186        while(of<dest_length){
187          *(dp+of)=n^*(bp+of);
188          of++;
189        }
190      } else{
191        while(of<dest_length){
192          *(dp+of)=*(ap+of)^n;
193          of++;
194        }
195      }
196    }
197   
198    GameState *r = new GameState;
199    r->id = b->id;
200    r->size = dest_length;
201    r->diffed = true;
202    r->data = dp;
203    return r;
204  }
205
206  GameStateCompressed *GameStateManager::compress_(GameState *a) {
207    COUT(5) << "compressing gamestate" << std::endl;
208    int size = a->size;
209    uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;
210    unsigned char* dest = (unsigned char*)malloc( buffer );
211    int retval;
212    //std::cout << "before ziped " << buffer << std::endl;
213    retval = compress( dest, &buffer, a->data, (uLong)size );
214    //std::cout << "after ziped " << buffer << std::endl;
215
216    switch ( retval ) {
217      case Z_OK: COUT(5) << "successfully compressed" << std::endl; break;
218      case Z_MEM_ERROR: COUT(1) << "not enough memory available in gamestate.compress" << std::endl; 
219      return NULL;
220      case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer in gamestate.compress" << std::endl;
221      return NULL;
222      case Z_DATA_ERROR: COUT(2) << "decompress: data corrupted in gamestate.compress" << std::endl;
223      return NULL;
224    }
225
226    GameStateCompressed *compressedGamestate = new GameStateCompressed;
227    compressedGamestate->compsize = buffer;
228//     std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl;
229    compressedGamestate->normsize = size;
230//     std::cout << "compressedGamestate.normsize = size; " << size << std::endl;
231    compressedGamestate->id = a->id;
232    compressedGamestate->data = dest;
233    compressedGamestate->diffed = a->diffed;
234
235    return compressedGamestate;
236  }
237
238  void GameStateManager::ackGameState(int clientID, int gamestateID) {
239    ClientInformation *temp = head_->findClient(clientID);
240    int curid = temp->getID();
241    // decrease usage of gamestate and save it
242    deleteUnusedGameState(curid);
243    //increase gamestateused
244    ++gameStateUsed.find(gamestateID)->second;
245    temp->setGamestateID(gamestateID);
246    /*
247    GameState *old = clientGameState[clientID];
248    deleteUnusedGameState(old);
249    clientGameState[clientID]=idGameState[gamestateID];*/
250  }
251
252  bool GameStateManager::deleteUnusedGameState(int gamestateID) {
253    int used = --(gameStateUsed.find(gamestateID)->second);
254    if(id-gamestateID>KEEP_GAMESTATES && used==0){
255      // delete gamestate
256      delete gameStateMap.find(gamestateID)->second;
257      gameStateMap.erase(gamestateID);
258      return true;
259    }
260    return false;
261  }
262
263}
Note: See TracBrowser for help on using the repository browser.