Changeset 777 for code/branches/FICN/src/network/GameStateManager.cc
- Timestamp:
- Dec 31, 2007, 7:40:23 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/FICN/src/network/GameStateManager.cc
r656 r777 1 1 /* 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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 27 28 28 // … … 37 37 // 38 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" 39 47 #include "GameStateManager.h" 40 48 41 namespace network { 42 43 GameStateManager::GameStateManager(ClientInformation *head) 49 namespace network 44 50 { 45 id=0; 46 head_=head; 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 != 0; ++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 GameState r = {b->id, dest_length, dp}; 185 return r; 186 } 187 188 GameStateCompressed GameStateManager::compress_(GameState *a) { 189 //COUT(2) << "compressing gamestate" << std::endl; 190 int size = a->size; 191 uLongf buffer = (uLongf)((a->size + 12)*1.01)+1; 192 unsigned char* dest = (unsigned char*)malloc( buffer ); 193 int retval; 194 //std::cout << "before ziped " << buffer << std::endl; 195 retval = compress( dest, &buffer, a->data, (uLong)size ); 196 //std::cout << "after ziped " << buffer << std::endl; 197 198 switch ( retval ) { 199 case Z_OK: std::cout << "successfully compressed" << std::endl; break; 200 case Z_MEM_ERROR: std::cout << "not enough memory available" << std::endl; break; 201 case Z_BUF_ERROR: std::cout << "not enough memory available in the buffer" << std::endl; break; 202 case Z_DATA_ERROR: std::cout << "decompress: data corrupted" << std::endl; break; 203 } 204 205 GameStateCompressed compressedGamestate; 206 compressedGamestate.compsize = buffer; 207 //std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl; 208 compressedGamestate.normsize = size; 209 //std::cout << "compressedGamestate.normsize = size; " << size << std::endl; 210 compressedGamestate.id = a->id; 211 compressedGamestate.data = dest; 212 compressedGamestate.diffed = a->diffed; 213 214 return compressedGamestate; 215 } 216 217 void GameStateManager::ackGameState(int clientID, int gamestateID) { 218 ClientInformation *temp = head_->findClient(clientID); 219 int curid = temp->getID(); 220 // decrease usage of gamestate and save it 221 deleteUnusedGameState(curid); 222 //increase gamestateused 223 ++gameStateUsed.find(gamestateID)->second; 224 temp->setGamestateID(gamestateID); 225 /* 226 GameState *old = clientGameState[clientID]; 227 deleteUnusedGameState(old); 228 clientGameState[clientID]=idGameState[gamestateID];*/ 229 } 230 231 bool GameStateManager::deleteUnusedGameState(int gamestateID) { 232 int used = --(gameStateUsed.find(gamestateID)->second); 233 if(id-gamestateID>KEEP_GAMESTATES && used==0){ 234 // delete gamestate 235 delete gameStateMap.find(gamestateID)->second; 236 gameStateMap.erase(gamestateID); 237 return true; 238 } 239 return false; 240 } 241 47 242 } 48 49 GameStateManager::~GameStateManager()50 {51 }52 53 void 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 61 GameStateCompressed GameStateManager::popGameState(int clientID){62 int gID = head_->findClient(clientID)->getGamestateID();63 std::cout << "popgamestate: sending gstate id: " << id << "diffed from: " << gID << std::endl;64 if(gID!=GAMESTATEID_INITIAL){65 GameState *client = gameStateMap[gID];66 GameState *server = reference;67 //head_->findClient(clientID)->setGamestateID(id);68 return encode(client, server);69 } else {70 GameState *server = reference;71 //head_->findClient(clientID)->setGamestateID(id);72 return encode(server);73 // return an undiffed gamestate and set appropriate flags74 }75 }76 77 78 79 /**80 * This function goes through the whole list of synchronisables and81 * saves all the synchronisables to a flat "list".82 * @return struct of type gamestate containing the size of the whole gamestate and a pointer linking to the flat list83 */84 GameState *GameStateManager::getSnapshot(int id)85 {86 //the size of the gamestate87 int totalsize=0;88 int memsize=1000;89 //the size of one specific synchronisable90 int tempsize=0;91 // get the start of the Synchronisable list92 orxonox::Iterator<Synchronisable> it;93 // struct for return value of Synchronisable::getData()94 syncData sync;95 96 GameState *retval=new GameState; //return value97 retval->id=id++;98 std::cout << "producing gamestate with id: " << retval->id << std::endl;99 // reserve a little memory and increase it later on100 //COUT(2) << "mallocing" << std::endl;101 retval->data = (unsigned char*)malloc(memsize);102 //COUT(2) << "malloced" << std::endl;103 104 // offset of memory functions105 int offset=0;106 // go through all Synchronisables107 for(it = orxonox::ObjectList<Synchronisable>::start(); it != 0; ++it){108 //std::cout << "gamestatemanager: in for loop" << std::endl;109 //get size of the synchronisable110 tempsize=it->getSize();111 //std::cout << "size of temp gamestate: " << tempsize << std::endl;112 //COUT(2) << "size of synchronisable: " << tempsize << std::endl;113 // add place for data and 3 ints (length,classid,objectid)114 totalsize+=tempsize+3*sizeof(int);115 //std::cout << "totalsize: " << totalsize << std::endl;116 // allocate additional space117 if(totalsize+tempsize>memsize){118 if(tempsize<1000){119 retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);120 memsize+=1000;121 } else {122 retval->data = (unsigned char *)realloc((void *)retval->data, totalsize+1000);123 memsize+=tempsize+1000;124 }125 }126 127 // run Synchronisable::getData with offset and additional place for 3 ints in between (for ids and length)128 sync=it->getData((retval->data)+offset+3*sizeof(int));129 *(retval->data+offset)=sync.length;130 *(retval->data+offset+sizeof(int))=sync.objectID;131 *(retval->data+offset+2*sizeof(int))=sync.classID;132 // increase data pointer133 offset+=tempsize+3*sizeof(int);134 }135 retval->size=totalsize;136 return retval;137 }138 139 140 141 GameStateCompressed GameStateManager::encode(GameState *a, GameState *b){142 //GameState r = diff(a,b);143 //r.diffed = true;144 GameState r = *b;145 r.diffed = false;146 return compress_(&r);147 }148 149 GameStateCompressed GameStateManager::encode(GameState *a){150 a->diffed=false;151 return compress_(a);152 }153 154 GameState GameStateManager::diff(GameState *a, GameState *b){155 unsigned char *ap = a->data, *bp = b->data;156 int of=0; // pointers offset157 int dest_length=0;158 if(a->size>=b->size)159 dest_length=a->size;160 else161 dest_length=b->size;162 unsigned char *dp = (unsigned char *)malloc(dest_length*sizeof(unsigned char));163 while(of<a->size && of<b->size){164 *(dp+of)=*(ap+of)^*(bp+of); // do the xor165 ++of;166 }167 if(a->size!=b->size){ // do we have to fill up ?168 unsigned char n=0;169 if(a->size<b->size){170 while(of<dest_length){171 *(dp+of)=n^*(bp+of);172 of++;173 }174 } else{175 while(of<dest_length){176 *(dp+of)=*(ap+of)^n;177 of++;178 }179 }180 }181 // should be finished now182 GameState r = {b->id, dest_length, dp};183 return r;184 }185 186 GameStateCompressed GameStateManager::compress_(GameState *a) {187 //COUT(2) << "compressing gamestate" << std::endl;188 int size = a->size;189 uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;190 unsigned char* dest = (unsigned char*)malloc( buffer );191 int retval;192 //std::cout << "before ziped " << buffer << std::endl;193 retval = compress( dest, &buffer, a->data, (uLong)size );194 //std::cout << "after ziped " << buffer << std::endl;195 196 switch ( retval ) {197 case Z_OK: std::cout << "successfully compressed" << std::endl; break;198 case Z_MEM_ERROR: std::cout << "not enough memory available" << std::endl; break;199 case Z_BUF_ERROR: std::cout << "not enough memory available in the buffer" << std::endl; break;200 case Z_DATA_ERROR: std::cout << "decompress: data corrupted" << std::endl; break;201 }202 203 GameStateCompressed compressedGamestate;204 compressedGamestate.compsize = buffer;205 //std::cout << "compressedGamestate.compsize = buffer; " << buffer << std::endl;206 compressedGamestate.normsize = size;207 //std::cout << "compressedGamestate.normsize = size; " << size << std::endl;208 compressedGamestate.id = a->id;209 compressedGamestate.data = dest;210 compressedGamestate.diffed = a->diffed;211 212 return compressedGamestate;213 }214 215 void GameStateManager::ackGameState(int clientID, int gamestateID){216 ClientInformation *temp = head_->findClient(clientID);217 int curid = temp->getID();218 // decrease usage of gamestate and save it219 deleteUnusedGameState(curid);220 //increase gamestateused221 ++gameStateUsed.find(gamestateID)->second;222 temp->setGamestateID(gamestateID);223 /*224 GameState *old = clientGameState[clientID];225 deleteUnusedGameState(old);226 clientGameState[clientID]=idGameState[gamestateID];*/227 }228 229 bool GameStateManager::deleteUnusedGameState(int gamestateID){230 int used = --(gameStateUsed.find(gamestateID)->second);231 if(id-gamestateID>KEEP_GAMESTATES && used==0){232 // delete gamestate233 delete gameStateMap.find(gamestateID)->second;234 gameStateMap.erase(gamestateID);235 return true;236 }237 return false;238 }239 240 }241 242
Note: See TracChangeset
for help on using the changeset viewer.