| [1505] | 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: | 
|---|
 | 23 |  *      Dumeni Manatschal, (C) 2007 | 
|---|
 | 24 |  *      Oliver Scheuss, (C) 2007 | 
|---|
 | 25 |  *   Co-authors: | 
|---|
 | 26 |  *      ... | 
|---|
 | 27 |  * | 
|---|
 | 28 |  */ | 
|---|
 | 29 |  | 
|---|
 | 30 |  | 
|---|
 | 31 | #include "Synchronisable.h" | 
|---|
 | 32 |  | 
|---|
| [3214] | 33 | #include <cstdlib> | 
|---|
| [1505] | 34 | #include "core/CoreIncludes.h" | 
|---|
| [5742] | 35 | #include "core/GameMode.h" | 
|---|
| [1735] | 36 | #include "core/BaseObject.h" | 
|---|
| [3214] | 37 | #include "network/Host.h" | 
|---|
| [1505] | 38 |  | 
|---|
| [2171] | 39 | namespace orxonox | 
|---|
| [1505] | 40 | { | 
|---|
| [1639] | 41 |  | 
|---|
| [2309] | 42 |   std::map<uint32_t, Synchronisable *> Synchronisable::objectMap_; | 
|---|
 | 43 |   std::queue<uint32_t> Synchronisable::deletedObjects_; | 
|---|
| [1639] | 44 |  | 
|---|
| [2171] | 45 |   uint8_t Synchronisable::state_=0x1; // detemines wheter we are server (default) or client | 
|---|
| [1639] | 46 |  | 
|---|
| [10624] | 47 |   RegisterAbstractClass(Synchronisable).inheritsFrom<OrxonoxInterface>(); | 
|---|
| [9667] | 48 |  | 
|---|
| [1505] | 49 |   /** | 
|---|
 | 50 |   * Constructor: | 
|---|
| [5929] | 51 |   * Initializes all Variables and sets the right objectID_ | 
|---|
| [1505] | 52 |   */ | 
|---|
| [9667] | 53 |   Synchronisable::Synchronisable(Context* context) | 
|---|
| [7163] | 54 |   { | 
|---|
| [9667] | 55 |       RegisterObject(Synchronisable); | 
|---|
| [1907] | 56 |     static uint32_t idCounter=0; | 
|---|
 | 57 |     objectMode_=0x1; // by default do not send data to server | 
|---|
| [7163] | 58 |     if ( GameMode::isMaster()/* || ( Host::running() && Host::isServer() )*/ ) | 
|---|
| [2171] | 59 |     { | 
|---|
| [5929] | 60 |       this->setObjectID( idCounter++ ); | 
|---|
| [2171] | 61 |     } | 
|---|
 | 62 |     else | 
|---|
| [5743] | 63 |     { | 
|---|
| [5929] | 64 |       objectID_=OBJECTID_UNKNOWN; | 
|---|
| [5743] | 65 |     } | 
|---|
| [5929] | 66 |     classID_ = static_cast<uint32_t>(-1); | 
|---|
| [6417] | 67 |  | 
|---|
| [3084] | 68 |     // set dataSize to 0 | 
|---|
 | 69 |     this->dataSize_ = 0; | 
|---|
| [2415] | 70 |     // set standard priority | 
|---|
| [3280] | 71 |     this->setPriority( Priority::Normal ); | 
|---|
| [2171] | 72 |  | 
|---|
| [9667] | 73 |     // get context id | 
|---|
 | 74 |     this->contextID_ = this->findContextID(context); | 
|---|
| [1505] | 75 |   } | 
|---|
 | 76 |  | 
|---|
| [1907] | 77 |   /** | 
|---|
| [2087] | 78 |    * Destructor: | 
|---|
| [5929] | 79 |    * Delete all callback objects and remove objectID_ from the objectMap_ | 
|---|
| [1907] | 80 |    */ | 
|---|
| [7163] | 81 |   Synchronisable::~Synchronisable() | 
|---|
 | 82 |   { | 
|---|
| [1534] | 83 |     // delete callback function objects | 
|---|
| [9667] | 84 |     if(!IdentifierManager::getInstance().isCreatingHierarchy()){ | 
|---|
| [3198] | 85 |       // remove object from the static objectMap | 
|---|
 | 86 |       if (this->objectMode_ != 0x0 && (Host::running() && Host::isServer())) | 
|---|
| [5929] | 87 |         deletedObjects_.push(objectID_); | 
|---|
| [1907] | 88 |     } | 
|---|
| [7163] | 89 |     // delete all Synchronisable Variables from syncList_ ( which are also in stringList_ ) | 
|---|
 | 90 |     for(std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin(); it!=syncList_.end(); it++) | 
|---|
| [3304] | 91 |       delete (*it); | 
|---|
| [7163] | 92 |     syncList_.clear(); | 
|---|
 | 93 |     stringList_.clear(); | 
|---|
| [7183] | 94 |     std::map<uint32_t, Synchronisable*>::iterator it2; | 
|---|
 | 95 |     it2 = objectMap_.find(objectID_); | 
|---|
 | 96 |     if (it2 != objectMap_.end()) | 
|---|
 | 97 |       objectMap_.erase(it2); | 
|---|
| [2485] | 98 |  | 
|---|
| [1505] | 99 |   } | 
|---|
| [1639] | 100 |  | 
|---|
| [9667] | 101 |   /** | 
|---|
 | 102 |    * @brief Returns the id of the context. | 
|---|
 | 103 |    * If the context is not Synchronisable, it moves on to its parent, recursively. | 
|---|
 | 104 |    */ | 
|---|
 | 105 |   uint32_t Synchronisable::findContextID(Context* context) | 
|---|
 | 106 |   { | 
|---|
 | 107 |       if (context == NULL) | 
|---|
 | 108 |           return OBJECTID_UNKNOWN; | 
|---|
| [2087] | 109 |  | 
|---|
| [9667] | 110 |       Synchronisable* synchronisableContext = orxonox_cast<Synchronisable*>(context); | 
|---|
 | 111 |       if (synchronisableContext != NULL) | 
|---|
 | 112 |           return synchronisableContext->getObjectID(); | 
|---|
 | 113 |       else | 
|---|
 | 114 |           return this->findContextID(context->getParentContext()); | 
|---|
 | 115 |   } | 
|---|
 | 116 |  | 
|---|
| [1907] | 117 |   /** | 
|---|
 | 118 |    * This function sets the internal mode for synchronisation | 
|---|
 | 119 |    * @param b true if this object is located on a client or on a server | 
|---|
 | 120 |    */ | 
|---|
| [7163] | 121 |   void Synchronisable::setClient(bool b) | 
|---|
 | 122 |   { | 
|---|
| [1505] | 123 |     if(b) // client | 
|---|
 | 124 |       state_=0x2; | 
|---|
 | 125 |     else  // server | 
|---|
 | 126 |       state_=0x1; | 
|---|
 | 127 |   } | 
|---|
| [1856] | 128 |  | 
|---|
| [1907] | 129 |   /** | 
|---|
 | 130 |    * This function fabricated a new synchrnisable (and children of it), sets calls updateData and create | 
|---|
 | 131 |    * After calling this function the mem pointer will be increased by the size of the needed data | 
|---|
 | 132 |    * @param mem pointer to where the appropriate data is located | 
|---|
 | 133 |    * @param mode defines the mode, how the data should be loaded | 
|---|
 | 134 |    * @return pointer to the newly created synchronisable | 
|---|
 | 135 |    */ | 
|---|
| [2171] | 136 |   Synchronisable *Synchronisable::fabricate(uint8_t*& mem, uint8_t mode) | 
|---|
| [1735] | 137 |   { | 
|---|
| [2662] | 138 |     SynchronisableHeader header(mem); | 
|---|
| [7801] | 139 |     if( header.isDiffed() ) | 
|---|
 | 140 |     { | 
|---|
 | 141 |       mem += header.getDataSize() + header.getSize(); | 
|---|
 | 142 |       return 0; | 
|---|
 | 143 |     } | 
|---|
 | 144 | //     assert( !header.isDiffed() ); | 
|---|
| [1856] | 145 |  | 
|---|
| [8858] | 146 |     orxout(verbose, context::network) << "fabricating object with id: " << header.getObjectID() << endl; | 
|---|
| [1856] | 147 |  | 
|---|
| [2662] | 148 |     Identifier* id = ClassByID(header.getClassID()); | 
|---|
| [2485] | 149 |     if (!id) | 
|---|
 | 150 |     { | 
|---|
| [3088] | 151 |         for(int i = 0; i<160; i++) | 
|---|
| [8858] | 152 |             orxout(user_error, context::network) << "classid: " << i << " identifier: " << ClassByID(i) << endl; | 
|---|
| [10624] | 153 |         orxout(user_error, context::network) << "Assertion failed: Could not find Identifier for ClassID " << header.getClassID() << endl; | 
|---|
| [8858] | 154 |         orxout(user_error, context::network) << "Possible reason for this error: Client received a synchronizable object whose class has no factory." << endl; | 
|---|
| [2485] | 155 |         abort(); | 
|---|
 | 156 |     } | 
|---|
| [1907] | 157 |     assert(id); | 
|---|
| [9667] | 158 |     Context* context = 0; | 
|---|
 | 159 |     if (header.getContextID() != OBJECTID_UNKNOWN) | 
|---|
| [2087] | 160 |     { | 
|---|
| [9667] | 161 |       Synchronisable* synchronisable_context = Synchronisable::getSynchronisable(header.getContextID()); | 
|---|
 | 162 |       if (!synchronisable_context) | 
|---|
| [2087] | 163 |       { | 
|---|
| [7163] | 164 |         mem += header.getDataSize()+SynchronisableHeader::getSize(); //.TODO: this suckz.... remove size from header | 
|---|
| [2662] | 165 |         assert(0); // TODO: uncomment this if we have a clean objecthierarchy (with destruction of children of objects) ^^ | 
|---|
| [2087] | 166 |         return 0; | 
|---|
 | 167 |       } | 
|---|
 | 168 |       else | 
|---|
| [9667] | 169 |         context = orxonox_cast<Context*>(synchronisable_context); | 
|---|
| [2087] | 170 |     } | 
|---|
| [9667] | 171 |     else | 
|---|
 | 172 |       context = Context::getRootContext(); | 
|---|
 | 173 |  | 
|---|
| [2662] | 174 |     assert(getSynchronisable(header.getObjectID())==0);   //make sure no object with this id exists | 
|---|
| [9667] | 175 |     BaseObject *bo = orxonox_cast<BaseObject*>(id->fabricate(context)); | 
|---|
| [2087] | 176 |     assert(bo); | 
|---|
| [3325] | 177 |     Synchronisable *no = orxonox_cast<Synchronisable*>(bo); | 
|---|
| [1735] | 178 |     assert(no); | 
|---|
| [5929] | 179 |     assert( Synchronisable::objectMap_.find(header.getObjectID()) == Synchronisable::objectMap_.end() ); | 
|---|
 | 180 |     no->setObjectID(header.getObjectID()); | 
|---|
| [9667] | 181 |     //no->contextID=header.getContextID(); //TODO: remove this | 
|---|
| [5929] | 182 |     no->setClassID(header.getClassID()); | 
|---|
| [9667] | 183 |     assert(no->contextID_ == header.getContextID()); | 
|---|
| [5929] | 184 |     //assert(no->classID_ == header.getClassID()); | 
|---|
| [8858] | 185 |     orxout(verbose, context::network) << "fabricate objectID_: " << no->objectID_ << " classID_: " << no->classID_ << endl; | 
|---|
| [1735] | 186 |           // update data and create object/entity... | 
|---|
| [2087] | 187 |     bool b = no->updateData(mem, mode, true); | 
|---|
| [1907] | 188 |     assert(b); | 
|---|
| [2087] | 189 |     if (b) | 
|---|
 | 190 |     { | 
|---|
| [2245] | 191 | //        b = no->create(); | 
|---|
| [2087] | 192 |         assert(b); | 
|---|
 | 193 |     } | 
|---|
| [1907] | 194 |     return no; | 
|---|
 | 195 |   } | 
|---|
 | 196 |  | 
|---|
| [2087] | 197 |  | 
|---|
| [1907] | 198 |   /** | 
|---|
| [5929] | 199 |    * Finds and deletes the Synchronisable with the appropriate objectID_ | 
|---|
 | 200 |    * @param objectID_ objectID_ of the Synchronisable | 
|---|
| [1907] | 201 |    * @return true/false | 
|---|
 | 202 |    */ | 
|---|
| [7163] | 203 |   bool Synchronisable::deleteObject(uint32_t objectID_) | 
|---|
 | 204 |   { | 
|---|
| [5929] | 205 |     if(!getSynchronisable(objectID_)) | 
|---|
| [1735] | 206 |       return false; | 
|---|
| [5929] | 207 |     assert(getSynchronisable(objectID_)->objectID_==objectID_); | 
|---|
 | 208 |     Synchronisable *s = getSynchronisable(objectID_); | 
|---|
| [1907] | 209 |     if(s) | 
|---|
| [5929] | 210 |       s->destroy(); // or delete? | 
|---|
| [1907] | 211 |     else | 
|---|
| [1735] | 212 |       return false; | 
|---|
 | 213 |     return true; | 
|---|
 | 214 |   } | 
|---|
| [2087] | 215 |  | 
|---|
| [1907] | 216 |   /** | 
|---|
| [5929] | 217 |    * This function looks up the objectID_ in the objectMap_ and returns a pointer to the right Synchronisable | 
|---|
 | 218 |    * @param objectID_ objectID_ of the Synchronisable | 
|---|
 | 219 |    * @return pointer to the Synchronisable with the objectID_ | 
|---|
| [1907] | 220 |    */ | 
|---|
| [7163] | 221 |   Synchronisable* Synchronisable::getSynchronisable(uint32_t objectID_) | 
|---|
 | 222 |   { | 
|---|
| [2309] | 223 |     std::map<uint32_t, Synchronisable*>::iterator it1; | 
|---|
| [5929] | 224 |     it1 = objectMap_.find(objectID_); | 
|---|
| [2171] | 225 |     if (it1 != objectMap_.end()) | 
|---|
 | 226 |       return it1->second; | 
|---|
| [3198] | 227 |     // if the objects not in the map it should'nt exist at all anymore | 
|---|
| [1907] | 228 |     return NULL; | 
|---|
 | 229 |   } | 
|---|
 | 230 |  | 
|---|
| [2087] | 231 |  | 
|---|
| [1505] | 232 |   /** | 
|---|
| [5929] | 233 |    * This function takes all SynchronisableVariables out of the Synchronisable and saves them together with the size, objectID_ and classID_ to the given memory | 
|---|
| [1735] | 234 |    * takes a pointer to already allocated memory (must have at least getSize bytes length) | 
|---|
| [1751] | 235 |    * structure of the bitstream: | 
|---|
| [5929] | 236 |    * |totalsize,objectID_,classID_,var1,var2,string1_length,string1,var3,...| | 
|---|
| [1907] | 237 |    * length of varx: size saved int syncvarlist | 
|---|
 | 238 |    * @param mem pointer to allocated memory with enough size | 
|---|
| [7801] | 239 |    * @param sizes vector containing sizes of all objects in gamestate (to be appended) | 
|---|
| [1907] | 240 |    * @param id gamestateid of the gamestate to be saved (important for priorities) | 
|---|
 | 241 |    * @param mode defines the direction in which the data will be send/received | 
|---|
 | 242 |    *             0x1: server->client | 
|---|
| [7801] | 243 |    *             0x2: client->server | 
|---|
| [1907] | 244 |    *             0x3: bidirectional | 
|---|
| [2087] | 245 |    * @return true: if !doSync or if everything was successfully saved | 
|---|
| [1735] | 246 |    */ | 
|---|
| [7163] | 247 |   uint32_t Synchronisable::getData(uint8_t*& mem, std::vector<uint32_t>& sizes, int32_t id, uint8_t mode) | 
|---|
 | 248 |   { | 
|---|
 | 249 |     unsigned int test = 0; | 
|---|
| [2171] | 250 |     if(mode==0x0) | 
|---|
 | 251 |       mode=state_; | 
|---|
| [1907] | 252 |     //if this tick is we dont synchronise, then abort now | 
|---|
| [8329] | 253 |     if(!doSync(/*id,*/ mode)) | 
|---|
| [3084] | 254 |       return 0; | 
|---|
| [2309] | 255 |     uint32_t tempsize = 0; | 
|---|
| [3304] | 256 | #ifndef NDEBUG | 
|---|
| [7163] | 257 |     uint8_t* oldmem = mem; | 
|---|
| [5929] | 258 |     if (this->classID_==0) | 
|---|
| [8858] | 259 |       orxout(internal_info, context::network) << "classid 0 " << this->getIdentifier()->getName() << endl; | 
|---|
| [3304] | 260 | #endif | 
|---|
| [2087] | 261 |  | 
|---|
| [5929] | 262 |     if (this->classID_ == static_cast<uint32_t>(-1)) | 
|---|
 | 263 |         this->classID_ = this->getIdentifier()->getNetworkID(); | 
|---|
| [2087] | 264 |  | 
|---|
| [5929] | 265 |     assert(ClassByID(this->classID_)); | 
|---|
 | 266 |     assert(this->classID_==this->getIdentifier()->getNetworkID()); | 
|---|
 | 267 |     assert(this->objectID_!=OBJECTID_UNKNOWN); | 
|---|
| [3084] | 268 |     std::vector<SynchronisableVariableBase*>::iterator i; | 
|---|
| [1856] | 269 |  | 
|---|
| [1735] | 270 |     // start copy header | 
|---|
| [2662] | 271 |     SynchronisableHeader header(mem); | 
|---|
 | 272 |     mem += SynchronisableHeader::getSize(); | 
|---|
| [1735] | 273 |     // end copy header | 
|---|
| [1856] | 274 |  | 
|---|
| [8858] | 275 |     orxout(verbose_more, context::network) << "getting data from objectID_: " << objectID_ << ", classID_: " << classID_ << endl; | 
|---|
 | 276 | //     orxout(verbose, context::network) << "objectid: " << this->objectID_ << ":"; | 
|---|
| [1735] | 277 |     // copy to location | 
|---|
| [7163] | 278 |     for(i=syncList_.begin(); i!=syncList_.end(); ++i) | 
|---|
 | 279 |     { | 
|---|
 | 280 |       uint32_t varsize = (*i)->getData( mem, mode ); | 
|---|
| [8858] | 281 | //       orxout(verbose, context::network) << " " << varsize; | 
|---|
| [7163] | 282 |       tempsize += varsize; | 
|---|
 | 283 |       sizes.push_back(varsize); | 
|---|
 | 284 |       ++test; | 
|---|
| [3084] | 285 |       //tempsize += (*i)->getSize( mode ); | 
|---|
| [1735] | 286 |     } | 
|---|
| [7801] | 287 |     assert(tempsize!=0);  // if this happens an empty object (with no variables) would be transmitted | 
|---|
| [8858] | 288 | //     orxout(verbose, context::network) << endl; | 
|---|
| [6417] | 289 |  | 
|---|
| [5929] | 290 |     header.setObjectID( this->objectID_ ); | 
|---|
| [9667] | 291 |     header.setContextID( this->contextID_ ); | 
|---|
| [5929] | 292 |     header.setClassID( this->classID_ ); | 
|---|
| [3084] | 293 |     header.setDataSize( tempsize ); | 
|---|
| [7163] | 294 |     assert( tempsize == mem-oldmem-SynchronisableHeader::getSize() ); | 
|---|
 | 295 |     assert( test == this->getNrOfVariables() ); | 
|---|
 | 296 |     header.setDiffed(false); | 
|---|
 | 297 |     tempsize += SynchronisableHeader::getSize(); | 
|---|
| [6417] | 298 |  | 
|---|
| [3084] | 299 | #ifndef NDEBUG | 
|---|
 | 300 |     uint32_t size; | 
|---|
 | 301 |     size=getSize(id, mode); | 
|---|
| [1735] | 302 |     assert(tempsize==size); | 
|---|
| [3084] | 303 | #endif | 
|---|
 | 304 |     return tempsize; | 
|---|
| [1735] | 305 |   } | 
|---|
| [1505] | 306 |  | 
|---|
| [1856] | 307 |  | 
|---|
| [1505] | 308 |   /** | 
|---|
| [1907] | 309 |    * This function takes a bytestream and loads the data into the registered variables | 
|---|
 | 310 |    * @param mem pointer to the bytestream | 
|---|
 | 311 |    * @param mode same as in getData | 
|---|
| [8327] | 312 |    * @param forceCallback this makes updateData call each callback | 
|---|
| [1735] | 313 |    * @return true/false | 
|---|
 | 314 |    */ | 
|---|
| [7163] | 315 |   bool Synchronisable::updateData(uint8_t*& mem, uint8_t mode, bool forceCallback) | 
|---|
 | 316 |   { | 
|---|
| [1735] | 317 |     if(mode==0x0) | 
|---|
 | 318 |       mode=state_; | 
|---|
| [8329] | 319 |      | 
|---|
| [7163] | 320 |     if(syncList_.empty()) | 
|---|
 | 321 |     { | 
|---|
| [8858] | 322 |       orxout(internal_warning, context::network) << "Synchronisable::updateData syncList_ is empty" << endl; | 
|---|
| [2419] | 323 |       assert(0); | 
|---|
| [1735] | 324 |       return false; | 
|---|
 | 325 |     } | 
|---|
| [1856] | 326 |  | 
|---|
| [2245] | 327 |     uint8_t* data=mem; | 
|---|
| [1735] | 328 |     // start extract header | 
|---|
| [7163] | 329 |     SynchronisableHeaderLight syncHeaderLight(mem); | 
|---|
 | 330 |     assert(syncHeaderLight.getObjectID()==this->getObjectID()); | 
|---|
| [8329] | 331 |      | 
|---|
 | 332 |     if( !this->doReceive(mode) ) | 
|---|
 | 333 |     { | 
|---|
 | 334 |       uint32_t headerSize; | 
|---|
 | 335 |       if( syncHeaderLight.isDiffed() ) | 
|---|
 | 336 |         headerSize = SynchronisableHeaderLight::getSize(); | 
|---|
 | 337 |       else | 
|---|
 | 338 |         headerSize = SynchronisableHeader::getSize(); | 
|---|
 | 339 |       mem += syncHeaderLight.getDataSize() + headerSize; | 
|---|
 | 340 |       return true; | 
|---|
 | 341 |     } | 
|---|
| [1856] | 342 |  | 
|---|
| [8858] | 343 |     //orxout(verbose_more, context::network) << "Synchronisable: objectID_ " << syncHeader.getObjectID() << ", classID_ " << syncHeader.getClassID() << " size: " << syncHeader.getDataSize() << " synchronising data" << endl; | 
|---|
| [7163] | 344 |     if( !syncHeaderLight.isDiffed() ) | 
|---|
| [2245] | 345 |     { | 
|---|
| [7163] | 346 |       SynchronisableHeader syncHeader2(mem); | 
|---|
 | 347 |       assert( this->getClassID() == syncHeader2.getClassID() ); | 
|---|
| [9667] | 348 |       assert( this->getContextID() == syncHeader2.getContextID() ); | 
|---|
| [7163] | 349 |       mem += SynchronisableHeader::getSize(); | 
|---|
 | 350 |       std::vector<SynchronisableVariableBase *>::iterator i; | 
|---|
| [7801] | 351 |       for(i=syncList_.begin(); i!=syncList_.end(); ++i) | 
|---|
| [7163] | 352 |       { | 
|---|
 | 353 |         assert( mem <= data+syncHeader2.getDataSize()+SynchronisableHeader::getSize() ); // always make sure we don't exceed the datasize in our stream | 
|---|
 | 354 |         (*i)->putData( mem, mode, forceCallback ); | 
|---|
 | 355 |       } | 
|---|
 | 356 |       assert(mem == data+syncHeaderLight.getDataSize()+SynchronisableHeader::getSize() ); | 
|---|
| [1735] | 357 |     } | 
|---|
| [7163] | 358 |     else | 
|---|
 | 359 |     { | 
|---|
 | 360 |       mem += SynchronisableHeaderLight::getSize(); | 
|---|
| [8858] | 361 | //       orxout(debug_output, context::network) << "objectID: " << this->objectID_ << endl; | 
|---|
| [7163] | 362 |       while( mem < data+syncHeaderLight.getDataSize()+SynchronisableHeaderLight::getSize() ) | 
|---|
 | 363 |       { | 
|---|
 | 364 |         VariableID varID = *(VariableID*)mem; | 
|---|
| [8858] | 365 | //         orxout(debug_output, context::network) << "varID: " << varID << endl; | 
|---|
| [7163] | 366 |         assert( varID < syncList_.size() ); | 
|---|
 | 367 |         mem += sizeof(VariableID); | 
|---|
 | 368 |         syncList_[varID]->putData( mem, mode, forceCallback ); | 
|---|
 | 369 |       } | 
|---|
 | 370 |       assert(mem == data+syncHeaderLight.getDataSize()+SynchronisableHeaderLight::getSize() ); | 
|---|
 | 371 |     } | 
|---|
| [1735] | 372 |     return true; | 
|---|
 | 373 |   } | 
|---|
| [1505] | 374 |  | 
|---|
 | 375 |   /** | 
|---|
 | 376 |   * This function returns the total amount of bytes needed by getData to save the whole content of the variables | 
|---|
| [1907] | 377 |   * @param id id of the gamestate | 
|---|
 | 378 |   * @param mode same as getData | 
|---|
| [1505] | 379 |   * @return amount of bytes | 
|---|
 | 380 |   */ | 
|---|
| [7163] | 381 |   uint32_t Synchronisable::getSize(int32_t id, uint8_t mode) | 
|---|
 | 382 |   { | 
|---|
 | 383 |     uint32_t tsize=SynchronisableHeader::getSize(); | 
|---|
| [3084] | 384 |     if (mode==0x0) | 
|---|
| [1505] | 385 |       mode=state_; | 
|---|
| [8329] | 386 |     if (!doSync(/*id, */mode)) | 
|---|
| [2171] | 387 |       return 0; | 
|---|
| [3084] | 388 |     assert( mode==state_ ); | 
|---|
 | 389 |     tsize += this->dataSize_; | 
|---|
 | 390 |     std::vector<SynchronisableVariableBase*>::iterator i; | 
|---|
| [7163] | 391 |     for(i=stringList_.begin(); i!=stringList_.end(); ++i) | 
|---|
 | 392 |     { | 
|---|
| [2245] | 393 |       tsize += (*i)->getSize( mode ); | 
|---|
| [1505] | 394 |     } | 
|---|
 | 395 |     return tsize; | 
|---|
 | 396 |   } | 
|---|
| [1639] | 397 |  | 
|---|
| [1735] | 398 |   /** | 
|---|
| [1907] | 399 |    * This function determines, wheter the object should be saved to the bytestream (according to its syncmode/direction) | 
|---|
| [8327] | 400 |    * @param mode Synchronisation mode (toclient, toserver or bidirectional) | 
|---|
| [1907] | 401 |    * @return true/false | 
|---|
| [1735] | 402 |    */ | 
|---|
| [8329] | 403 |   bool Synchronisable::doSync(/*int32_t id,*/ uint8_t mode) | 
|---|
| [7163] | 404 |   { | 
|---|
| [8327] | 405 | //     if(mode==0x0) | 
|---|
 | 406 | //       mode=state_; | 
|---|
 | 407 |     assert(mode!=0x0); | 
|---|
| [7163] | 408 |     return ( (this->objectMode_ & mode)!=0 && (!syncList_.empty() ) ); | 
|---|
| [1735] | 409 |   } | 
|---|
| [8329] | 410 |    | 
|---|
 | 411 |   /** | 
|---|
 | 412 |    * This function determines, wheter the object should accept data from the bytestream (according to its syncmode/direction) | 
|---|
 | 413 |    * @param mode Synchronisation mode (toclient, toserver or bidirectional) | 
|---|
 | 414 |    * @return true/false | 
|---|
 | 415 |    */ | 
|---|
 | 416 |   bool Synchronisable::doReceive( uint8_t mode) | 
|---|
 | 417 |   { | 
|---|
 | 418 |     //return mode != this->objectMode_ || this->objectMode_ == ObjectDirection::Bidirectional; | 
|---|
 | 419 |     return true; | 
|---|
 | 420 |   } | 
|---|
| [1856] | 421 |  | 
|---|
| [1907] | 422 |   /** | 
|---|
 | 423 |    * This function sets the synchronisation mode of the object | 
|---|
| [2171] | 424 |    * If set to 0x0 variables will not be synchronised at all | 
|---|
| [1907] | 425 |    * If set to 0x1 variables will only be synchronised to the client | 
|---|
 | 426 |    * If set to 0x2 variables will only be synchronised to the server | 
|---|
 | 427 |    * If set to 0x3 variables will be synchronised bidirectionally (only if set so in registerVar) | 
|---|
 | 428 |    * @param mode same as in registerVar | 
|---|
 | 429 |    */ | 
|---|
| [7163] | 430 |   void Synchronisable::setSyncMode(uint8_t mode) | 
|---|
 | 431 |   { | 
|---|
| [2087] | 432 |     assert(mode==0x0 || mode==0x1 || mode==0x2 || mode==0x3); | 
|---|
| [5929] | 433 |     this->objectMode_=mode; | 
|---|
| [1505] | 434 |   } | 
|---|
 | 435 |  | 
|---|
| [6417] | 436 |   template <> void Synchronisable::registerVariable( std::string& variable, uint8_t mode, NetworkCallbackBase *cb, bool bidirectional) | 
|---|
 | 437 |   { | 
|---|
 | 438 |     SynchronisableVariableBase* sv; | 
|---|
 | 439 |     if (bidirectional) | 
|---|
 | 440 |       sv = new SynchronisableVariableBidirectional<std::string>(variable, mode, cb); | 
|---|
 | 441 |     else | 
|---|
 | 442 |       sv = new SynchronisableVariable<std::string>(variable, mode, cb); | 
|---|
| [7163] | 443 |     syncList_.push_back(sv); | 
|---|
 | 444 |     stringList_.push_back(sv); | 
|---|
| [6417] | 445 |   } | 
|---|
| [2485] | 446 |  | 
|---|
| [7163] | 447 | template <> void Synchronisable::unregisterVariable( std::string& variable ) | 
|---|
 | 448 |   { | 
|---|
 | 449 |     bool unregistered_nonexistent_variable = true; | 
|---|
 | 450 |     std::vector<SynchronisableVariableBase*>::iterator it = syncList_.begin(); | 
|---|
 | 451 |     while(it!=syncList_.end()) | 
|---|
 | 452 |     { | 
|---|
 | 453 |       if( ((*it)->getReference()) == &variable ) | 
|---|
 | 454 |       { | 
|---|
 | 455 |         delete (*it); | 
|---|
 | 456 |         syncList_.erase(it); | 
|---|
 | 457 |         unregistered_nonexistent_variable = false; | 
|---|
 | 458 |         break; | 
|---|
 | 459 |       } | 
|---|
 | 460 |       else | 
|---|
 | 461 |         ++it; | 
|---|
 | 462 |     } | 
|---|
 | 463 |     assert(unregistered_nonexistent_variable == false); | 
|---|
 | 464 |      | 
|---|
 | 465 |     it = stringList_.begin(); | 
|---|
 | 466 |     while(it!=stringList_.end()) | 
|---|
 | 467 |     { | 
|---|
 | 468 |       if( ((*it)->getReference()) == &variable ) | 
|---|
 | 469 |       { | 
|---|
 | 470 |         delete (*it); | 
|---|
 | 471 |         stringList_.erase(it); | 
|---|
 | 472 |         return; | 
|---|
 | 473 |       } | 
|---|
 | 474 |       else | 
|---|
 | 475 |         ++it; | 
|---|
 | 476 |     } | 
|---|
 | 477 |     unregistered_nonexistent_variable = true; | 
|---|
 | 478 |     assert(unregistered_nonexistent_variable == false); //if we reach this point something went wrong: | 
|---|
 | 479 |     // the variable has not been registered before | 
|---|
 | 480 |   } | 
|---|
| [6417] | 481 |  | 
|---|
| [7163] | 482 |  | 
|---|
| [1505] | 483 | } | 
|---|