| [1711] | 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: | 
|---|
| [3084] | 23 | *      Oliver Scheuss | 
|---|
| [1711] | 24 | *   Co-authors: | 
|---|
|  | 25 | *      ... | 
|---|
|  | 26 | * | 
|---|
|  | 27 | */ | 
|---|
|  | 28 |  | 
|---|
| [1701] | 29 | #include "Gamestate.h" | 
|---|
| [2773] | 30 | #include <enet/enet.h> | 
|---|
|  | 31 | #include <zlib.h> | 
|---|
|  | 32 | #include <cassert> | 
|---|
| [2662] | 33 | #include "../GamestateHandler.h" | 
|---|
|  | 34 | #include "../synchronisable/Synchronisable.h" | 
|---|
|  | 35 | #include "../TrafficControl.h" | 
|---|
| [2896] | 36 | #include "core/GameMode.h" | 
|---|
| [1763] | 37 | #include "core/CoreIncludes.h" | 
|---|
| [1751] | 38 | #include "core/Iterator.h" | 
|---|
| [1701] | 39 |  | 
|---|
|  | 40 |  | 
|---|
|  | 41 |  | 
|---|
|  | 42 |  | 
|---|
| [2171] | 43 | namespace orxonox { | 
|---|
| [1701] | 44 |  | 
|---|
|  | 45 | namespace packet { | 
|---|
|  | 46 |  | 
|---|
| [2662] | 47 | #define GAMESTATE_START(data) (data + GamestateHeader::getSize()) | 
|---|
| [1740] | 48 |  | 
|---|
| [1907] | 49 | #define PACKET_FLAG_GAMESTATE  ENET_PACKET_FLAG_RELIABLE | 
|---|
| [2087] | 50 |  | 
|---|
| [2662] | 51 |  | 
|---|
| [1701] | 52 | Gamestate::Gamestate() | 
|---|
|  | 53 | { | 
|---|
| [1907] | 54 | flags_ = flags_ | PACKET_FLAG_GAMESTATE; | 
|---|
| [2662] | 55 | header_ = 0; | 
|---|
| [1701] | 56 | } | 
|---|
|  | 57 |  | 
|---|
| [1907] | 58 | Gamestate::Gamestate(uint8_t *data, unsigned int clientID): | 
|---|
| [1711] | 59 | Packet(data, clientID) | 
|---|
| [1701] | 60 | { | 
|---|
| [1907] | 61 | flags_ = flags_ | PACKET_FLAG_GAMESTATE; | 
|---|
| [2662] | 62 | header_ = new GamestateHeader(data_); | 
|---|
| [1701] | 63 | } | 
|---|
|  | 64 |  | 
|---|
| [1907] | 65 | Gamestate::Gamestate(uint8_t *data) | 
|---|
|  | 66 | { | 
|---|
|  | 67 | flags_ = flags_ | PACKET_FLAG_GAMESTATE; | 
|---|
|  | 68 | data_=data; | 
|---|
| [2662] | 69 | header_ = new GamestateHeader(data_); | 
|---|
| [1907] | 70 | } | 
|---|
| [1701] | 71 |  | 
|---|
| [2662] | 72 | Gamestate::Gamestate(const Gamestate& g) : | 
|---|
|  | 73 | Packet( *(Packet*)&g ) | 
|---|
|  | 74 | { | 
|---|
|  | 75 | flags_ = flags_ | PACKET_FLAG_GAMESTATE; | 
|---|
|  | 76 | header_ = new GamestateHeader(data_); | 
|---|
|  | 77 | } | 
|---|
| [1907] | 78 |  | 
|---|
| [2662] | 79 |  | 
|---|
| [1701] | 80 | Gamestate::~Gamestate() | 
|---|
|  | 81 | { | 
|---|
|  | 82 | } | 
|---|
|  | 83 |  | 
|---|
| [2171] | 84 | bool Gamestate::collectData(int id, uint8_t mode) | 
|---|
| [1701] | 85 | { | 
|---|
| [2662] | 86 | assert(this->header_==0); // make sure the header didn't exist before | 
|---|
|  | 87 | uint32_t tempsize=0, currentsize=0; | 
|---|
| [1751] | 88 | assert(data_==0); | 
|---|
| [2662] | 89 | uint32_t size = calcGamestateSize(id, mode); | 
|---|
| [1740] | 90 |  | 
|---|
| [1701] | 91 | COUT(4) << "G.ST.Man: producing gamestate with id: " << id << std::endl; | 
|---|
|  | 92 | if(size==0) | 
|---|
|  | 93 | return false; | 
|---|
| [2662] | 94 | data_ = new uint8_t[size + GamestateHeader::getSize()]; | 
|---|
| [1701] | 95 | if(!data_){ | 
|---|
|  | 96 | COUT(2) << "GameStateManager: could not allocate memory" << std::endl; | 
|---|
|  | 97 | return false; | 
|---|
|  | 98 | } | 
|---|
| [2662] | 99 |  | 
|---|
|  | 100 | // create the header object | 
|---|
|  | 101 | header_ = new GamestateHeader(data_); | 
|---|
| [2087] | 102 |  | 
|---|
| [1701] | 103 | //start collect data synchronisable by synchronisable | 
|---|
| [1907] | 104 | uint8_t *mem=data_; | 
|---|
| [2662] | 105 | mem += GamestateHeader::getSize(); | 
|---|
| [2171] | 106 | ObjectList<Synchronisable>::iterator it; | 
|---|
|  | 107 | for(it = ObjectList<Synchronisable>::begin(); it; ++it){ | 
|---|
| [2662] | 108 |  | 
|---|
| [3084] | 109 | //     tempsize=it->getSize(id, mode); | 
|---|
|  | 110 |  | 
|---|
|  | 111 | tempsize = it->getData(mem, id, mode); | 
|---|
|  | 112 | if ( tempsize != 0 ) | 
|---|
|  | 113 | dataVector_.push_back( obj(it->getObjectID(), it->getCreatorID(), tempsize, mem-data_) ); | 
|---|
|  | 114 |  | 
|---|
| [2662] | 115 | #ifndef NDEBUG | 
|---|
| [1701] | 116 | if(currentsize+tempsize > size){ | 
|---|
| [2171] | 117 | assert(0); // if we don't use multithreading this part shouldn't be neccessary | 
|---|
| [1701] | 118 | // start allocate additional memory | 
|---|
|  | 119 | COUT(3) << "G.St.Man: need additional memory" << std::endl; | 
|---|
| [2171] | 120 | ObjectList<Synchronisable>::iterator temp = it; | 
|---|
| [2662] | 121 | uint32_t addsize=tempsize; | 
|---|
| [1701] | 122 | while(++temp) | 
|---|
| [1907] | 123 | addsize+=temp->getSize(id, mode); | 
|---|
| [2662] | 124 | data_ = (uint8_t *)realloc(data_, GamestateHeader::getSize() + currentsize + addsize); | 
|---|
| [1701] | 125 | if(!data_) | 
|---|
|  | 126 | return false; | 
|---|
|  | 127 | size = currentsize+addsize; | 
|---|
|  | 128 | }// stop allocate additional memory | 
|---|
| [2662] | 129 | #endif | 
|---|
| [3084] | 130 | //     if(!it->getData(mem, id, mode)) | 
|---|
|  | 131 | //       return false; // mem pointer gets automatically increased because of call by reference | 
|---|
| [1701] | 132 | // increase size counter by size of current synchronisable | 
|---|
|  | 133 | currentsize+=tempsize; | 
|---|
|  | 134 | } | 
|---|
| [1740] | 135 |  | 
|---|
|  | 136 |  | 
|---|
| [1701] | 137 | //start write gamestate header | 
|---|
| [2662] | 138 | header_->setDataSize( currentsize ); | 
|---|
|  | 139 | header_->setID( id ); | 
|---|
|  | 140 | header_->setDiffed( false ); | 
|---|
|  | 141 | header_->setComplete( true ); | 
|---|
|  | 142 | header_->setCompressed( false ); | 
|---|
| [1701] | 143 | //stop write gamestate header | 
|---|
| [1740] | 144 |  | 
|---|
| [1701] | 145 | COUT(5) << "G.ST.Man: Gamestate size: " << currentsize << std::endl; | 
|---|
|  | 146 | COUT(5) << "G.ST.Man: 'estimated' (and corrected) Gamestate size: " << size << std::endl; | 
|---|
|  | 147 | return true; | 
|---|
|  | 148 | } | 
|---|
|  | 149 |  | 
|---|
| [2171] | 150 | bool Gamestate::spreadData(uint8_t mode) | 
|---|
| [1701] | 151 | { | 
|---|
| [2662] | 152 | COUT(4) << "processing gamestate with id " << header_->getID() << endl; | 
|---|
| [1751] | 153 | assert(data_); | 
|---|
| [2662] | 154 | assert(!header_->isCompressed()); | 
|---|
|  | 155 | assert(!header_->isDiffed()); | 
|---|
|  | 156 | uint8_t *mem=data_+GamestateHeader::getSize(); | 
|---|
| [1907] | 157 | Synchronisable *s; | 
|---|
| [1740] | 158 |  | 
|---|
| [1907] | 159 | // update the data of the objects we received | 
|---|
| [2662] | 160 | while(mem < data_+GamestateHeader::getSize()+header_->getDataSize()){ | 
|---|
|  | 161 | SynchronisableHeader objectheader(mem); | 
|---|
| [1701] | 162 |  | 
|---|
| [2662] | 163 | s = Synchronisable::getSynchronisable( objectheader.getObjectID() ); | 
|---|
| [1907] | 164 | if(!s) | 
|---|
| [1701] | 165 | { | 
|---|
| [2896] | 166 | if (!GameMode::isMaster()) | 
|---|
| [2662] | 167 | { | 
|---|
|  | 168 | Synchronisable::fabricate(mem, mode); | 
|---|
|  | 169 | } | 
|---|
|  | 170 | else | 
|---|
|  | 171 | { | 
|---|
|  | 172 | mem += objectheader.getDataSize(); | 
|---|
|  | 173 | } | 
|---|
| [1701] | 174 | } | 
|---|
| [1907] | 175 | else | 
|---|
|  | 176 | { | 
|---|
|  | 177 | bool b = s->updateData(mem, mode); | 
|---|
|  | 178 | assert(b); | 
|---|
|  | 179 | } | 
|---|
| [1701] | 180 | } | 
|---|
| [2662] | 181 | // In debug mode, check first, whether there are no duplicate objectIDs | 
|---|
|  | 182 | #ifndef NDEBUG | 
|---|
| [3084] | 183 | if(this->getID()%1000==0){ | 
|---|
|  | 184 | std::list<uint32_t> v1; | 
|---|
|  | 185 | ObjectList<Synchronisable>::iterator it; | 
|---|
|  | 186 | for (it = ObjectList<Synchronisable>::begin(); it != ObjectList<Synchronisable>::end(); ++it) { | 
|---|
|  | 187 | if (it->getObjectID() == OBJECTID_UNKNOWN) { | 
|---|
|  | 188 | if (it->objectMode_ != 0x0) { | 
|---|
|  | 189 | COUT(0) << "Found object with OBJECTID_UNKNOWN on the client with objectMode != 0x0!" << std::endl; | 
|---|
|  | 190 | COUT(0) << "Possible reason for this error: Client created a synchronized object without the Server's approval." << std::endl; | 
|---|
|  | 191 | COUT(0) << "Objects class: " << it->getIdentifier()->getName() << std::endl; | 
|---|
|  | 192 | assert(false); | 
|---|
|  | 193 | } | 
|---|
| [2662] | 194 | } | 
|---|
| [3084] | 195 | else { | 
|---|
|  | 196 | std::list<uint32_t>::iterator it2; | 
|---|
|  | 197 | for (it2 = v1.begin(); it2 != v1.end(); ++it2) { | 
|---|
|  | 198 | if (it->getObjectID() == *it2) { | 
|---|
|  | 199 | COUT(0) << "Found duplicate objectIDs on the client!" << std::endl | 
|---|
|  | 200 | << "Are you sure you don't create a Sychnronisable objcect with 'new' \ | 
|---|
|  | 201 | that doesn't have objectMode = 0x0?" << std::endl; | 
|---|
|  | 202 | assert(false); | 
|---|
|  | 203 | } | 
|---|
| [2662] | 204 | } | 
|---|
| [3084] | 205 | v1.push_back(it->getObjectID()); | 
|---|
| [2662] | 206 | } | 
|---|
|  | 207 | } | 
|---|
|  | 208 | } | 
|---|
|  | 209 | #endif | 
|---|
|  | 210 |  | 
|---|
| [1701] | 211 | return true; | 
|---|
|  | 212 | } | 
|---|
|  | 213 |  | 
|---|
| [2662] | 214 | uint32_t Gamestate::getSize() const | 
|---|
| [1701] | 215 | { | 
|---|
| [1711] | 216 | assert(data_); | 
|---|
| [2662] | 217 | if(header_->isCompressed()) | 
|---|
|  | 218 | return header_->getCompSize()+GamestateHeader::getSize(); | 
|---|
| [1701] | 219 | else | 
|---|
|  | 220 | { | 
|---|
| [2662] | 221 | return header_->getDataSize()+GamestateHeader::getSize(); | 
|---|
| [1701] | 222 | } | 
|---|
|  | 223 | } | 
|---|
|  | 224 |  | 
|---|
| [1751] | 225 | bool Gamestate::operator==(packet::Gamestate gs){ | 
|---|
| [2662] | 226 | uint8_t *d1 = data_+GamestateHeader::getSize(); | 
|---|
|  | 227 | uint8_t *d2 = gs.data_+GamestateHeader::getSize(); | 
|---|
| [3084] | 228 | GamestateHeader* h1 = new GamestateHeader(data_); | 
|---|
|  | 229 | GamestateHeader* h2 = new GamestateHeader(gs.data_); | 
|---|
|  | 230 | assert(h1->getDataSize() == h2->getDataSize()); | 
|---|
| [1751] | 231 | assert(!isCompressed()); | 
|---|
|  | 232 | assert(!gs.isCompressed()); | 
|---|
| [3084] | 233 | return memcmp(d1, d2, h1->getDataSize())==0; | 
|---|
| [1751] | 234 | } | 
|---|
|  | 235 |  | 
|---|
| [1701] | 236 | bool Gamestate::process() | 
|---|
|  | 237 | { | 
|---|
| [1705] | 238 | return GamestateHandler::addGamestate(this, getClientID()); | 
|---|
| [1701] | 239 | } | 
|---|
|  | 240 |  | 
|---|
| [1907] | 241 |  | 
|---|
|  | 242 |  | 
|---|
| [1701] | 243 | bool Gamestate::compressData() | 
|---|
|  | 244 | { | 
|---|
| [2662] | 245 | assert(data_); | 
|---|
|  | 246 | assert(!header_->isCompressed()); | 
|---|
|  | 247 | uLongf buffer = (uLongf)(((header_->getDataSize() + 12)*1.01)+1); | 
|---|
| [1701] | 248 | if(buffer==0) | 
|---|
|  | 249 | return false; | 
|---|
| [1740] | 250 |  | 
|---|
| [2662] | 251 | uint8_t *ndata = new uint8_t[buffer+GamestateHeader::getSize()]; | 
|---|
|  | 252 | uint8_t *dest = ndata + GamestateHeader::getSize(); | 
|---|
|  | 253 | uint8_t *source = data_ + GamestateHeader::getSize(); | 
|---|
| [1701] | 254 | int retval; | 
|---|
| [2662] | 255 | retval = compress( dest, &buffer, source, (uLong)(header_->getDataSize()) ); | 
|---|
| [1701] | 256 | switch ( retval ) { | 
|---|
|  | 257 | case Z_OK: COUT(5) << "G.St.Man: compress: successfully compressed" << std::endl; break; | 
|---|
| [1751] | 258 | case Z_MEM_ERROR: COUT(1) << "G.St.Man: compress: not enough memory available in gamestate.compress" << std::endl; return false; | 
|---|
|  | 259 | case Z_BUF_ERROR: COUT(2) << "G.St.Man: compress: not enough memory available in the buffer in gamestate.compress" << std::endl; return false; | 
|---|
|  | 260 | case Z_DATA_ERROR: COUT(2) << "G.St.Man: compress: data corrupted in gamestate.compress" << std::endl; return false; | 
|---|
| [1701] | 261 | } | 
|---|
|  | 262 |  | 
|---|
|  | 263 | //copy and modify header | 
|---|
| [2662] | 264 | GamestateHeader *temp = header_; | 
|---|
|  | 265 | header_ = new GamestateHeader(ndata, temp); | 
|---|
|  | 266 | delete temp; | 
|---|
| [1701] | 267 | //delete old data | 
|---|
|  | 268 | delete[] data_; | 
|---|
|  | 269 | //save new data | 
|---|
|  | 270 | data_ = ndata; | 
|---|
| [2662] | 271 | header_->setCompSize( buffer ); | 
|---|
|  | 272 | header_->setCompressed( true ); | 
|---|
|  | 273 | COUT(5) << "gamestate compress datasize: " << header_->getDataSize() << " compsize: " << header_->getCompSize() << std::endl; | 
|---|
| [1701] | 274 | return true; | 
|---|
|  | 275 | } | 
|---|
|  | 276 | bool Gamestate::decompressData() | 
|---|
|  | 277 | { | 
|---|
| [2662] | 278 | assert(data_); | 
|---|
|  | 279 | assert(header_->isCompressed()); | 
|---|
|  | 280 | COUT(4) << "GameStateClient: uncompressing gamestate. id: " << header_->getID() << ", baseid: " << header_->getBaseID() << ", datasize: " << header_->getDataSize() << ", compsize: " << header_->getCompSize() << std::endl; | 
|---|
|  | 281 | uint32_t datasize = header_->getDataSize(); | 
|---|
|  | 282 | uint32_t compsize = header_->getCompSize(); | 
|---|
|  | 283 | uint32_t bufsize; | 
|---|
| [1907] | 284 | bufsize = datasize; | 
|---|
| [1751] | 285 | assert(bufsize!=0); | 
|---|
| [2662] | 286 | uint8_t *ndata = new uint8_t[bufsize + GamestateHeader::getSize()]; | 
|---|
|  | 287 | uint8_t *dest = ndata + GamestateHeader::getSize(); | 
|---|
|  | 288 | uint8_t *source = data_ + GamestateHeader::getSize(); | 
|---|
| [1701] | 289 | int retval; | 
|---|
| [1751] | 290 | uLongf length=bufsize; | 
|---|
|  | 291 | retval = uncompress( dest, &length, source, (uLong)compsize ); | 
|---|
| [1701] | 292 | switch ( retval ) { | 
|---|
|  | 293 | case Z_OK: COUT(5) << "successfully decompressed" << std::endl; break; | 
|---|
|  | 294 | case Z_MEM_ERROR: COUT(1) << "not enough memory available" << std::endl; return false; | 
|---|
|  | 295 | case Z_BUF_ERROR: COUT(2) << "not enough memory available in the buffer" << std::endl; return false; | 
|---|
|  | 296 | case Z_DATA_ERROR: COUT(2) << "data corrupted (zlib)" << std::endl; return false; | 
|---|
|  | 297 | } | 
|---|
| [1752] | 298 |  | 
|---|
| [1701] | 299 | //copy over the header | 
|---|
| [2662] | 300 | GamestateHeader *temp = header_; | 
|---|
|  | 301 | header_ = new GamestateHeader( data_, header_ ); | 
|---|
|  | 302 | delete temp; | 
|---|
| [2087] | 303 |  | 
|---|
|  | 304 | if (this->bDataENetAllocated_){ | 
|---|
|  | 305 | // Memory was allocated by ENet. --> We let it be since enet_packet_destroy will | 
|---|
|  | 306 | // deallocated it anyway. So data and packet stay together. | 
|---|
|  | 307 | this->bDataENetAllocated_ = false; | 
|---|
|  | 308 | } | 
|---|
|  | 309 | else{ | 
|---|
|  | 310 | // We allocated the memory in the first place (unlikely). So we destroy the old data | 
|---|
|  | 311 | // and overwrite it with the new decompressed data. | 
|---|
|  | 312 | delete[] this->data_; | 
|---|
|  | 313 | } | 
|---|
|  | 314 |  | 
|---|
| [1751] | 315 | //set new pointers | 
|---|
| [1701] | 316 | data_ = ndata; | 
|---|
| [2662] | 317 | header_->setCompressed( false ); | 
|---|
|  | 318 | assert(header_->getDataSize()==datasize); | 
|---|
|  | 319 | assert(header_->getCompSize()==compsize); | 
|---|
| [1701] | 320 | return true; | 
|---|
|  | 321 | } | 
|---|
|  | 322 |  | 
|---|
|  | 323 | Gamestate *Gamestate::diff(Gamestate *base) | 
|---|
|  | 324 | { | 
|---|
| [2662] | 325 | assert(data_); | 
|---|
|  | 326 | assert(!header_->isCompressed()); | 
|---|
|  | 327 | assert(!header_->isDiffed()); | 
|---|
|  | 328 | GamestateHeader diffHeader(base->data_); | 
|---|
| [1907] | 329 | uint8_t *basep = GAMESTATE_START(base->data_), *gs = GAMESTATE_START(this->data_); | 
|---|
| [2662] | 330 | uint32_t of=0; // pointers offset | 
|---|
|  | 331 | uint32_t dest_length=0; | 
|---|
|  | 332 | dest_length=header_->getDataSize(); | 
|---|
| [1701] | 333 | if(dest_length==0) | 
|---|
|  | 334 | return NULL; | 
|---|
| [2662] | 335 | uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()]; | 
|---|
|  | 336 | uint8_t *dest = ndata + GamestateHeader::getSize(); | 
|---|
|  | 337 | while(of < diffHeader.getDataSize() && of < header_->getDataSize()){ | 
|---|
| [1701] | 338 | *(dest+of)=*(basep+of)^*(gs+of); // do the xor | 
|---|
|  | 339 | ++of; | 
|---|
|  | 340 | } | 
|---|
| [2662] | 341 | if(diffHeader.getDataSize()!=header_->getDataSize()){ | 
|---|
| [1907] | 342 | uint8_t n=0; | 
|---|
| [2662] | 343 | if(diffHeader.getDataSize() < header_->getDataSize()){ | 
|---|
| [1701] | 344 | while(of<dest_length){ | 
|---|
|  | 345 | *(dest+of)=n^*(gs+of); | 
|---|
|  | 346 | of++; | 
|---|
|  | 347 | } | 
|---|
|  | 348 | } | 
|---|
|  | 349 | } | 
|---|
|  | 350 |  | 
|---|
| [1751] | 351 | Gamestate *g = new Gamestate(ndata, getClientID()); | 
|---|
| [2662] | 352 | *(g->header_) = *header_; | 
|---|
|  | 353 | g->header_->setDiffed( true ); | 
|---|
|  | 354 | g->header_->setBaseID( base->getID() ); | 
|---|
| [1751] | 355 | g->flags_=flags_; | 
|---|
|  | 356 | g->packetDirection_ = packetDirection_; | 
|---|
| [1701] | 357 | return g; | 
|---|
|  | 358 | } | 
|---|
|  | 359 |  | 
|---|
| [3084] | 360 | // Gamestate *Gamestate::diff(Gamestate *base) | 
|---|
|  | 361 | // { | 
|---|
|  | 362 | //   assert(data_); | 
|---|
|  | 363 | //   assert(!header_->isCompressed()); | 
|---|
|  | 364 | //   assert(!header_->isDiffed()); | 
|---|
|  | 365 | //   GamestateHeader diffHeader(base->data_); | 
|---|
|  | 366 | //   uint8_t *basep = GAMESTATE_START(base->data_), *gs = GAMESTATE_START(this->data_); | 
|---|
|  | 367 | //   uint32_t of=0; // pointers offset | 
|---|
|  | 368 | //   uint32_t dest_length=0; | 
|---|
|  | 369 | //   dest_length=header_->getDataSize(); | 
|---|
|  | 370 | //   if(dest_length==0) | 
|---|
|  | 371 | //     return NULL; | 
|---|
|  | 372 | //   uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()]; | 
|---|
|  | 373 | //   uint8_t *dest = ndata + GamestateHeader::getSize(); | 
|---|
|  | 374 | // | 
|---|
|  | 375 | // | 
|---|
|  | 376 | //   // LOOP-UNROLLED DIFFING | 
|---|
|  | 377 | //   uint32_t *dest32 = (uint32_t*)dest, *base32 = (uint32_t*)basep, *gs32 = (uint32_t*)gs; | 
|---|
|  | 378 | //   // diff in 4-byte steps | 
|---|
|  | 379 | //   while( of < (uint32_t)(header_->getDataSize())/4 ){ | 
|---|
|  | 380 | //     if( of < (uint32_t)(diffHeader.getDataSize())/4 ) | 
|---|
|  | 381 | //     { | 
|---|
|  | 382 | //       *(dest32+of)=*(base32+of) ^ *(gs32+of); // do the xor | 
|---|
|  | 383 | //       ++of; | 
|---|
|  | 384 | //     } | 
|---|
|  | 385 | //     else | 
|---|
|  | 386 | //     { | 
|---|
|  | 387 | //       *(dest32+of)=*(gs32+of); // same as 0 ^ *(gs32+of) | 
|---|
|  | 388 | //       ++of; | 
|---|
|  | 389 | //     } | 
|---|
|  | 390 | //   } | 
|---|
|  | 391 | //   for( unsigned int of2 = 0; of2 < header_->getDataSize()%4; ++of2 ) | 
|---|
|  | 392 | //   { | 
|---|
|  | 393 | //     if( of*4+of2 < diffHeader.getDataSize() ) | 
|---|
|  | 394 | //     { | 
|---|
|  | 395 | //       *(dest+4*of+of2)=*(basep+4*of+of2) ^ *(gs+4*of+of2); // do the xor | 
|---|
|  | 396 | //     } | 
|---|
|  | 397 | //     else | 
|---|
|  | 398 | //     { | 
|---|
|  | 399 | //       *(dest+4*of+of2)=*(gs+4*of+of2); // same as 0 ^ *(gs32+of) | 
|---|
|  | 400 | //     } | 
|---|
|  | 401 | //   } | 
|---|
|  | 402 | // | 
|---|
|  | 403 | //   Gamestate *g = new Gamestate(ndata, getClientID()); | 
|---|
|  | 404 | //   *(g->header_) = *header_; | 
|---|
|  | 405 | //   g->header_->setDiffed( true ); | 
|---|
|  | 406 | //   g->header_->setBaseID( base->getID() ); | 
|---|
|  | 407 | //   g->flags_=flags_; | 
|---|
|  | 408 | //   g->packetDirection_ = packetDirection_; | 
|---|
|  | 409 | //   return g; | 
|---|
|  | 410 | // } | 
|---|
|  | 411 |  | 
|---|
| [2662] | 412 | Gamestate* Gamestate::doSelection(unsigned int clientID, unsigned int targetSize){ | 
|---|
| [1907] | 413 | assert(data_); | 
|---|
| [2662] | 414 | std::list<obj>::iterator it; | 
|---|
| [2087] | 415 |  | 
|---|
| [1907] | 416 | // allocate memory for new data | 
|---|
| [2662] | 417 | uint8_t *gdata = new uint8_t[header_->getDataSize()+GamestateHeader::getSize()]; | 
|---|
| [1907] | 418 | // create a gamestate out of it | 
|---|
|  | 419 | Gamestate *gs = new Gamestate(gdata); | 
|---|
| [2662] | 420 | uint8_t *newdata = gdata + GamestateHeader::getSize(); | 
|---|
| [1907] | 421 | uint8_t *origdata = GAMESTATE_START(data_); | 
|---|
| [2087] | 422 |  | 
|---|
| [1907] | 423 | //copy the GamestateHeader | 
|---|
| [2662] | 424 | assert(gs->header_); | 
|---|
|  | 425 | *(gs->header_) = *header_; | 
|---|
| [2087] | 426 |  | 
|---|
| [2662] | 427 | uint32_t objectOffset; | 
|---|
|  | 428 | unsigned int objectsize, destsize=0; | 
|---|
|  | 429 | // TODO: Why is this variable not used? | 
|---|
|  | 430 | //Synchronisable *object; | 
|---|
| [2087] | 431 |  | 
|---|
| [2662] | 432 | //call TrafficControl | 
|---|
| [3084] | 433 | TrafficControl::getInstance()->processObjectList( clientID, header_->getID(), dataVector_ ); | 
|---|
| [2662] | 434 |  | 
|---|
| [1907] | 435 | //copy in the zeros | 
|---|
| [3084] | 436 | //   std::list<obj>::iterator itt; | 
|---|
|  | 437 | //   COUT(0) << "myvector contains:"; | 
|---|
|  | 438 | //   for ( itt=dataVector_.begin() ; itt!=dataVector_.end(); itt++ ) | 
|---|
|  | 439 | //     COUT(0) << " " << (*itt).objID; | 
|---|
|  | 440 | //   COUT(0) << endl; | 
|---|
|  | 441 | for(it=dataVector_.begin(); it!=dataVector_.end();){ | 
|---|
| [2662] | 442 | SynchronisableHeader oldobjectheader(origdata); | 
|---|
|  | 443 | SynchronisableHeader newobjectheader(newdata); | 
|---|
|  | 444 | if ( (*it).objSize == 0 ) | 
|---|
|  | 445 | { | 
|---|
|  | 446 | ++it; | 
|---|
|  | 447 | continue; | 
|---|
|  | 448 | } | 
|---|
|  | 449 | objectsize = oldobjectheader.getDataSize(); | 
|---|
|  | 450 | objectOffset=SynchronisableHeader::getSize(); //skip the size and the availableData variables in the objectheader | 
|---|
|  | 451 | if ( (*it).objID == oldobjectheader.getObjectID() ){ | 
|---|
|  | 452 | memcpy(newdata, origdata, objectsize); | 
|---|
|  | 453 | assert(newobjectheader.isDataAvailable()==true); | 
|---|
|  | 454 | ++it; | 
|---|
| [1907] | 455 | }else{ | 
|---|
| [2662] | 456 | newobjectheader = oldobjectheader; | 
|---|
|  | 457 | newobjectheader.setDataAvailable(false); | 
|---|
| [2171] | 458 | memset(newdata+objectOffset, 0, objectsize-objectOffset); | 
|---|
| [1907] | 459 | } | 
|---|
|  | 460 | newdata += objectsize; | 
|---|
|  | 461 | origdata += objectsize; | 
|---|
| [2662] | 462 | destsize += objectsize; | 
|---|
| [1907] | 463 | } | 
|---|
| [2662] | 464 | #ifndef NDEBUG | 
|---|
|  | 465 | uint32_t origsize = destsize; | 
|---|
|  | 466 | while ( origsize < header_->getDataSize() ) | 
|---|
|  | 467 | { | 
|---|
|  | 468 | SynchronisableHeader oldobjectheader(origdata); | 
|---|
|  | 469 | objectsize = oldobjectheader.getDataSize(); | 
|---|
|  | 470 | origdata += objectsize; | 
|---|
|  | 471 | origsize += objectsize; | 
|---|
| [1907] | 472 | } | 
|---|
| [2662] | 473 | assert(origsize==header_->getDataSize()); | 
|---|
|  | 474 | assert(destsize!=0); | 
|---|
|  | 475 | #endif | 
|---|
|  | 476 | gs->header_->setDataSize( destsize ); | 
|---|
| [1907] | 477 | return gs; | 
|---|
|  | 478 | } | 
|---|
|  | 479 |  | 
|---|
| [2087] | 480 |  | 
|---|
| [1701] | 481 | Gamestate *Gamestate::undiff(Gamestate *base) | 
|---|
|  | 482 | { | 
|---|
| [2662] | 483 | assert(this && base);assert(data_); | 
|---|
|  | 484 | assert(header_->isDiffed()); | 
|---|
|  | 485 | assert(!header_->isCompressed() && !base->header_->isCompressed()); | 
|---|
| [1907] | 486 | uint8_t *basep = GAMESTATE_START(base->data_); | 
|---|
|  | 487 | uint8_t *gs = GAMESTATE_START(this->data_); | 
|---|
| [2662] | 488 | uint32_t of=0; // pointers offset | 
|---|
|  | 489 | uint32_t dest_length=0; | 
|---|
|  | 490 | dest_length=header_->getDataSize(); | 
|---|
| [1701] | 491 | if(dest_length==0) | 
|---|
|  | 492 | return NULL; | 
|---|
| [2662] | 493 | uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()]; | 
|---|
|  | 494 | uint8_t *dest = ndata + GamestateHeader::getSize(); | 
|---|
|  | 495 | while(of < base->header_->getDataSize() && of < header_->getDataSize()){ | 
|---|
| [1701] | 496 | *(dest+of)=*(basep+of)^*(gs+of); // do the xor | 
|---|
|  | 497 | ++of; | 
|---|
|  | 498 | } | 
|---|
| [2662] | 499 | if(base->header_->getDataSize()!=header_->getDataSize()){ | 
|---|
| [1907] | 500 | uint8_t n=0; | 
|---|
| [2662] | 501 | if(base->header_->getDataSize() < header_->getDataSize()){ | 
|---|
| [1701] | 502 | while(of < dest_length){ | 
|---|
|  | 503 | *(dest+of)=n^*(gs+of); | 
|---|
|  | 504 | of++; | 
|---|
|  | 505 | } | 
|---|
|  | 506 | } | 
|---|
|  | 507 | } | 
|---|
| [1751] | 508 | Gamestate *g = new Gamestate(ndata, getClientID()); | 
|---|
| [2662] | 509 | assert(g->header_); | 
|---|
|  | 510 | *(g->header_) = *header_; | 
|---|
|  | 511 | g->header_->setDiffed( false ); | 
|---|
| [1751] | 512 | g->flags_=flags_; | 
|---|
|  | 513 | g->packetDirection_ = packetDirection_; | 
|---|
|  | 514 | assert(!g->isDiffed()); | 
|---|
|  | 515 | assert(!g->isCompressed()); | 
|---|
| [1701] | 516 | return g; | 
|---|
|  | 517 | } | 
|---|
|  | 518 |  | 
|---|
|  | 519 |  | 
|---|
| [2662] | 520 | uint32_t Gamestate::calcGamestateSize(int32_t id, uint8_t mode) | 
|---|
| [1701] | 521 | { | 
|---|
| [2662] | 522 | uint32_t size=0; | 
|---|
| [1701] | 523 | // get the start of the Synchronisable list | 
|---|
| [2171] | 524 | ObjectList<Synchronisable>::iterator it; | 
|---|
| [1701] | 525 | // get total size of gamestate | 
|---|
| [2171] | 526 | for(it = ObjectList<Synchronisable>::begin(); it; ++it) | 
|---|
| [1907] | 527 | size+=it->getSize(id, mode); // size of the actual data of the synchronisable | 
|---|
| [1701] | 528 | return size; | 
|---|
|  | 529 | } | 
|---|
|  | 530 |  | 
|---|
| [2662] | 531 | } //namespace packet | 
|---|
|  | 532 | } //namespace orxonox | 
|---|