Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 934 was 871, checked in by landauf, 17 years ago

merged core branch to trunk

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