| [12177] | 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 |  *      Oliver Scheuss <scheusso [at] ee.ethz.ch> | 
|---|
 | 24 |  *   Co-authors: | 
|---|
 | 25 |  *      ... | 
|---|
 | 26 |  * | 
|---|
 | 27 |  */ | 
|---|
 | 28 |  | 
|---|
 | 29 | #include "TrafficControl.h" | 
|---|
 | 30 |  | 
|---|
 | 31 | #include <cassert> | 
|---|
 | 32 | #include <functional> | 
|---|
 | 33 |  | 
|---|
 | 34 | #include "core/CoreIncludes.h" | 
|---|
 | 35 | #include "core/config/ConfigValueIncludes.h" | 
|---|
 | 36 | #include "synchronisable/Synchronisable.h" | 
|---|
 | 37 |  | 
|---|
 | 38 | namespace orxonox { | 
|---|
 | 39 |  | 
|---|
 | 40 |   static constexpr unsigned int SCHED_PRIORITY_OFFSET = static_cast<unsigned int>(-1); | 
|---|
 | 41 |   namespace arg = std::placeholders; | 
|---|
 | 42 |  | 
|---|
 | 43 |   objInfo::objInfo(uint32_t ID, uint32_t creatorID, int32_t curGsID, int32_t diffGsID, uint32_t size, unsigned int prioperm, unsigned int priosched) | 
|---|
 | 44 |   { | 
|---|
 | 45 |     objID = ID; objCreatorID = creatorID; objCurGS = curGsID; objDiffGS = diffGsID; objSize = size; objValuePerm = prioperm; objValueSched = priosched; | 
|---|
 | 46 |   } | 
|---|
 | 47 |  | 
|---|
 | 48 |   objInfo::objInfo() | 
|---|
 | 49 |   { | 
|---|
 | 50 |     objID = OBJECTID_UNKNOWN; objCreatorID = OBJECTID_UNKNOWN; objCurGS = GAMESTATEID_INITIAL; objDiffGS = objCurGS; objSize = 0; objValuePerm = 0; objValueSched = 0; | 
|---|
 | 51 |   } | 
|---|
 | 52 |  | 
|---|
 | 53 |  | 
|---|
 | 54 |  | 
|---|
 | 55 |   obj::obj() | 
|---|
 | 56 |   { | 
|---|
 | 57 |     objID = OBJECTID_UNKNOWN; objCreatorID = OBJECTID_UNKNOWN; objSize = 0; objDataOffset = 0; | 
|---|
 | 58 |   } | 
|---|
 | 59 |   obj::obj( uint32_t ID, uint32_t creatorID, uint32_t size, uint32_t offset ) | 
|---|
 | 60 |   { | 
|---|
 | 61 |     objID = ID; objCreatorID = creatorID; objSize = size; objDataOffset = offset; | 
|---|
 | 62 |   } | 
|---|
 | 63 |  | 
|---|
 | 64 | /** | 
|---|
 | 65 | *Initializing protected members | 
|---|
 | 66 | */ | 
|---|
 | 67 |     TrafficControl *TrafficControl::instance_=nullptr; | 
|---|
 | 68 |  | 
|---|
 | 69 |     /** | 
|---|
 | 70 |     * @brief Constructor: assures that only one reference will be created and sets the pointer | 
|---|
 | 71 |     */ | 
|---|
 | 72 |     TrafficControl::TrafficControl() | 
|---|
 | 73 |     { | 
|---|
 | 74 |     RegisterObject(TrafficControl); | 
|---|
 | 75 |       assert(instance_==nullptr); | 
|---|
 | 76 |       instance_=this; | 
|---|
 | 77 |     this->setConfigValues(); | 
|---|
 | 78 |     } | 
|---|
 | 79 |  | 
|---|
 | 80 |     /** | 
|---|
 | 81 |     * @brief Destructor: resets the instance pointer to nullptr | 
|---|
 | 82 |     */ | 
|---|
 | 83 |     TrafficControl::~TrafficControl() | 
|---|
 | 84 |     { | 
|---|
 | 85 |       instance_=nullptr; | 
|---|
 | 86 |     } | 
|---|
 | 87 |  | 
|---|
 | 88 | /** | 
|---|
 | 89 | *Definition of public members | 
|---|
 | 90 | */ | 
|---|
 | 91 |  | 
|---|
 | 92 |   void TrafficControl::setConfigValues() | 
|---|
 | 93 |   { | 
|---|
 | 94 |     SetConfigValue ( bActive_, false ); | 
|---|
 | 95 |     SetConfigValue ( targetSize, 10000 ); | 
|---|
 | 96 |   } | 
|---|
 | 97 |  | 
|---|
 | 98 |   /** | 
|---|
 | 99 |   * sort-algorithm for sorting the objectlist after priorities | 
|---|
 | 100 |   */ | 
|---|
 | 101 |   bool TrafficControl::prioritySort(uint32_t clientID, obj i, obj j) | 
|---|
 | 102 |   { | 
|---|
 | 103 |     assert(clientListPerm_.find(clientID) != clientListPerm_.end());  //make sure the client exists in our list | 
|---|
 | 104 |     assert(clientListPerm_[clientID].find(i.objID) != clientListPerm_[clientID].end()); // make sure the object i is in the client list | 
|---|
 | 105 |     assert(clientListPerm_[clientID].find(j.objID) != clientListPerm_[clientID].end()); // make sure the object j is in the client list | 
|---|
 | 106 |  | 
|---|
 | 107 |     int prio1 = clientListPerm_[clientID][i.objID].objValuePerm + clientListPerm_[clientID][i.objID].objValueSched; | 
|---|
 | 108 |     int prio2 = clientListPerm_[clientID][j.objID].objValuePerm + clientListPerm_[clientID][j.objID].objValueSched; | 
|---|
 | 109 |     return prio1 < prio2; | 
|---|
 | 110 |   } | 
|---|
 | 111 |  | 
|---|
 | 112 |   /** | 
|---|
 | 113 |   * sort-algorithm for sorting the objectList after position in original data stream | 
|---|
 | 114 |   */ | 
|---|
 | 115 |   bool TrafficControl::dataSort(obj i, obj j) | 
|---|
 | 116 |   { | 
|---|
 | 117 |     int pos1 = i.objDataOffset; | 
|---|
 | 118 |     int pos2 = j.objDataOffset; | 
|---|
 | 119 |     return pos1 < pos2; | 
|---|
 | 120 |   } | 
|---|
 | 121 |  | 
|---|
 | 122 |  | 
|---|
 | 123 |  | 
|---|
 | 124 |     void TrafficControl::processObjectList(unsigned int clientID, unsigned int gamestateID, std::list<obj>& list) | 
|---|
 | 125 |     { | 
|---|
 | 126 |       currentClientID=clientID; | 
|---|
 | 127 |       currentGamestateID=gamestateID; | 
|---|
 | 128 |       evaluateList(clientID, list); | 
|---|
 | 129 |       return; | 
|---|
 | 130 |     } | 
|---|
 | 131 |  | 
|---|
 | 132 |   TrafficControl *TrafficControl::getInstance() | 
|---|
 | 133 |   { | 
|---|
 | 134 |     assert(instance_); | 
|---|
 | 135 |     return instance_; | 
|---|
 | 136 |   } | 
|---|
 | 137 |  | 
|---|
 | 138 |     void TrafficControl::ack(unsigned int clientID, unsigned int gamestateID) | 
|---|
 | 139 |     { | 
|---|
 | 140 |     if ( !this->bActive_ ) | 
|---|
 | 141 |       return; | 
|---|
 | 142 |     std::list<obj>::iterator itvec;  // iterator to iterate through the acked objects | 
|---|
 | 143 |  | 
|---|
 | 144 |     //assertions to make sure the maps already exist | 
|---|
 | 145 |     assert(clientListTemp_.find(clientID) != clientListTemp_.end() ); | 
|---|
 | 146 |     assert(clientListPerm_.find(clientID) != clientListPerm_.end() ); | 
|---|
 | 147 |     assert( clientListTemp_[clientID].find(gamestateID) != clientListTemp_[clientID].end() ); | 
|---|
 | 148 |  | 
|---|
 | 149 |     // shortcut for maps | 
|---|
 | 150 |     std::map<unsigned int, objInfo >& objectListPerm = clientListPerm_[clientID]; | 
|---|
 | 151 |     std::map<unsigned int, std::list<obj>>& objectListTemp = clientListTemp_[clientID]; | 
|---|
 | 152 |  | 
|---|
 | 153 |     for(itvec = objectListTemp[gamestateID].begin(); itvec != objectListTemp[gamestateID].end(); itvec++) | 
|---|
 | 154 |       { | 
|---|
 | 155 |       if(objectListPerm.find(itvec->objID) != objectListPerm.end()) // check whether the obj already exists in our lists | 
|---|
 | 156 |       { | 
|---|
 | 157 |         objectListPerm[itvec->objID].objCurGS = gamestateID; | 
|---|
 | 158 |         objectListPerm[itvec->objID].objValueSched = 0; //set scheduling value back | 
|---|
 | 159 |       } | 
|---|
 | 160 |       else | 
|---|
 | 161 |       { | 
|---|
 | 162 |         assert(0); | 
|---|
 | 163 |         objectListPerm[itvec->objID].objCurGS = gamestateID; | 
|---|
 | 164 |         objectListPerm[itvec->objID].objID = itvec->objID; | 
|---|
 | 165 |         objectListPerm[itvec->objID].objCreatorID = itvec->objCreatorID; | 
|---|
 | 166 |         objectListPerm[itvec->objID].objSize = itvec->objSize; | 
|---|
 | 167 |       } | 
|---|
 | 168 |       } | 
|---|
 | 169 |        // remove temporary list (with acked objects) from the map | 
|---|
 | 170 |     objectListTemp.erase( objectListTemp.find(gamestateID) ); | 
|---|
 | 171 |     } | 
|---|
 | 172 |  | 
|---|
 | 173 | /** | 
|---|
 | 174 | *Definition of private members | 
|---|
 | 175 | */ | 
|---|
 | 176 |  | 
|---|
 | 177 |     /** | 
|---|
 | 178 |     *updateClientListPerm | 
|---|
 | 179 |     *returns void | 
|---|
 | 180 |     */ | 
|---|
 | 181 |     void TrafficControl::insertinClientListPerm(unsigned int clientID, obj objinf) | 
|---|
 | 182 |     { | 
|---|
 | 183 |       std::map<unsigned int,std::map<unsigned int, objInfo>>::iterator itperm;//iterator clientListPerm over clientIDs | 
|---|
 | 184 |     unsigned int gsid=GAMESTATEID_INITIAL, gsdiff=currentGamestateID, prioperm=Synchronisable::getSynchronisable(objinf.objID)->getPriority(), priomom=0; | 
|---|
 | 185 |     clientListPerm_[clientID][objinf.objID] = objInfo(objinf.objID, objinf.objCreatorID,gsid,gsdiff, objinf.objSize,prioperm,priomom); | 
|---|
 | 186 |     } | 
|---|
 | 187 |  | 
|---|
 | 188 |   /** | 
|---|
 | 189 |   * updateClientListTemp | 
|---|
 | 190 |   * takes the shortened list which will be sent to the gsmanager and puts the *info into clientListTemp | 
|---|
 | 191 |   */ | 
|---|
 | 192 |   void TrafficControl::updateClientListTemp(std::list<obj>& list) | 
|---|
 | 193 |   { | 
|---|
 | 194 |     clientListTemp_[currentClientID][currentGamestateID] = list; | 
|---|
 | 195 |   } | 
|---|
 | 196 |  | 
|---|
 | 197 |   /** | 
|---|
 | 198 |   *cut | 
|---|
 | 199 |   *takes the current list that has to be returned to the gsmanager and shortens it in criteria of bandwidth of clientID(XY) | 
|---|
 | 200 |   */ | 
|---|
 | 201 |   void TrafficControl::cut(std::list<obj>& list, unsigned int targetsize) | 
|---|
 | 202 |   { | 
|---|
 | 203 |     unsigned int size=0; | 
|---|
 | 204 |     std::list<obj>::iterator itvec, ittemp; | 
|---|
 | 205 |     assert(!list.empty()); | 
|---|
 | 206 |     for(itvec = list.begin(); itvec != list.end();) | 
|---|
 | 207 |     { | 
|---|
 | 208 |       assert( itvec->objSize < 1000); | 
|---|
 | 209 |       if ( ( size + itvec->objSize ) < targetsize ) | 
|---|
 | 210 |       { | 
|---|
 | 211 |         size += itvec->objSize;//objSize is given in bytes | 
|---|
 | 212 |         ++itvec; | 
|---|
 | 213 |       } | 
|---|
 | 214 |       else | 
|---|
 | 215 |       { | 
|---|
 | 216 |         clientListPerm_[currentClientID][itvec->objID].objValueSched += SCHED_PRIORITY_OFFSET; // NOTE: SCHED_PRIORITY_OFFSET is negative | 
|---|
 | 217 |         list.erase(itvec, list.end()); | 
|---|
 | 218 |         break; | 
|---|
 | 219 |       } | 
|---|
 | 220 | //       printList(list, currentClientID); | 
|---|
 | 221 |     } | 
|---|
 | 222 |     assert(!list.empty()); | 
|---|
 | 223 |   } | 
|---|
 | 224 |  | 
|---|
 | 225 |  | 
|---|
 | 226 |     /** | 
|---|
 | 227 |     *evaluateList evaluates whether new obj are there, whether there are things to be updatet and manipulates all this. | 
|---|
 | 228 |     */ | 
|---|
 | 229 |     void TrafficControl::evaluateList(unsigned int clientID, std::list<obj>& list) | 
|---|
 | 230 |     { | 
|---|
 | 231 |  | 
|---|
 | 232 |     if( bActive_ ) | 
|---|
 | 233 |     { | 
|---|
 | 234 |       //now the sorting | 
|---|
 | 235 |  | 
|---|
 | 236 |       //compare listToProcess vs clientListPerm | 
|---|
 | 237 |       //if listToProcess contains new Objects, add them to clientListPerm | 
|---|
 | 238 |       std::list<obj>::iterator itvec; | 
|---|
 | 239 |  | 
|---|
 | 240 |       std::map<unsigned int, objInfo >& objectListPerm = clientListPerm_[clientID]; | 
|---|
 | 241 |  | 
|---|
 | 242 |       for( itvec=list.begin(); itvec != list.end(); itvec++) | 
|---|
 | 243 |       { | 
|---|
 | 244 |         if ( objectListPerm.find( itvec->objID) != objectListPerm.end() ) | 
|---|
 | 245 |         { | 
|---|
 | 246 |         // we already have the object in our map | 
|---|
 | 247 |         //obj bleibt in liste und permanente prio wird berechnet | 
|---|
 | 248 |           objectListPerm[itvec->objID].objDiffGS = currentGamestateID - objectListPerm[itvec->objID].objCurGS; | 
|---|
 | 249 |           continue;//check next objId | 
|---|
 | 250 |         } | 
|---|
 | 251 |         else | 
|---|
 | 252 |         { | 
|---|
 | 253 |         // insert the object into clientListPerm | 
|---|
 | 254 |           insertinClientListPerm(clientID,*itvec); | 
|---|
 | 255 |           continue;//check next objId | 
|---|
 | 256 |         } | 
|---|
 | 257 |       } | 
|---|
 | 258 |     //end compare listToProcess vs clientListPerm | 
|---|
 | 259 |  | 
|---|
 | 260 |       //sort copied list according to priorities | 
|---|
 | 261 |       // use std::bind here because we need to pass a memberfunction to stl sort | 
|---|
 | 262 | //       sort( list.begin(), list.end(), std::bind(&TrafficControl::prioritySort, this, clientID, arg::_1, arg::_2) ); | 
|---|
 | 263 |       list.sort( std::bind(&TrafficControl::prioritySort, this, clientID, arg::_1, arg::_2) ); | 
|---|
 | 264 |  | 
|---|
 | 265 | //       list.sort(std::bind(&TrafficControl::prioritySort, this, clientID, arg::_1, arg::_2) ); | 
|---|
 | 266 |  | 
|---|
 | 267 |       //now we check, that the creator of an object always exists on a client | 
|---|
 | 268 |       std::list<obj>::iterator itcreator; | 
|---|
 | 269 |       for(itvec = list.begin(); itvec != list.end(); itvec++) | 
|---|
 | 270 |       { | 
|---|
 | 271 |         fixCreatorDependencies(itvec, list, clientID); | 
|---|
 | 272 |       } | 
|---|
 | 273 |       //end of sorting | 
|---|
 | 274 |       //now the cutting, work the same obj out in processobjectlist and copiedlist, compression rate muss noch festgelegt werden. | 
|---|
 | 275 | //       printList(list, clientID); | 
|---|
 | 276 |       cut(list, targetSize); | 
|---|
 | 277 |       //now sort again after objDataOffset | 
|---|
 | 278 | //       sort(list.begin(), list.end(), std::bind(&TrafficControl::dataSort, this, arg::_1, arg::_2) ); | 
|---|
 | 279 |       list.sort( std::bind(&TrafficControl::dataSort, this, arg::_1, arg::_2) ); | 
|---|
 | 280 |  | 
|---|
 | 281 |       //diese Funktion updateClientList muss noch gemacht werden | 
|---|
 | 282 |       updateClientListTemp(list); | 
|---|
 | 283 |       //end of sorting | 
|---|
 | 284 |     } | 
|---|
 | 285 |   } | 
|---|
 | 286 |  | 
|---|
 | 287 |   void TrafficControl::printList(std::list<obj>& list, unsigned int clientID) | 
|---|
 | 288 |   { | 
|---|
 | 289 |     std::list<obj>::iterator it; | 
|---|
 | 290 |     orxout(debug_output, context::network) << "=========== Objectlist ===========" << endl; | 
|---|
 | 291 |     for( it=list.begin(); it!=list.end(); it++) | 
|---|
 | 292 |       orxout(debug_output, context::network) << "ObjectID: " << it->objID << " creatorID: " << it->objCreatorID << " Priority: " << clientListPerm_[clientID][it->objID].objValuePerm + clientListPerm_[clientID][it->objID].objValueSched << " size: " << it->objSize << endl; | 
|---|
 | 293 |   } | 
|---|
 | 294 |  | 
|---|
 | 295 |   void TrafficControl::fixCreatorDependencies(std::list<obj>::iterator it1, std::list<obj>& list, unsigned int clientID) | 
|---|
 | 296 |   { | 
|---|
 | 297 |     if ( it1->objCreatorID == OBJECTID_UNKNOWN ) | 
|---|
 | 298 |       return; | 
|---|
 | 299 |     if( clientListPerm_[clientID][it1->objCreatorID].objCurGS != GAMESTATEID_INITIAL ) | 
|---|
 | 300 |       return; | 
|---|
 | 301 |     std::list<obj>::iterator it2, it3=it1; | 
|---|
 | 302 |     for( it2 = ++it3; it2 != list.end(); it2++ ) | 
|---|
 | 303 |     { | 
|---|
 | 304 |       if( it2->objID == it1->objCreatorID ) | 
|---|
 | 305 |       { | 
|---|
 | 306 |         it3 = list.insert(it1, *it2); //insert creator before it1 | 
|---|
 | 307 |         list.erase(it2); | 
|---|
 | 308 | //         printList(list, clientID); | 
|---|
 | 309 |         fixCreatorDependencies( it3, list, clientID ); | 
|---|
 | 310 |         break; | 
|---|
 | 311 |       } | 
|---|
 | 312 |     } | 
|---|
 | 313 |   } | 
|---|
 | 314 |  | 
|---|
 | 315 |   void TrafficControl::clientDisconnected(unsigned int clientID) | 
|---|
 | 316 |   { | 
|---|
 | 317 |     if( clientListPerm_.find(clientID) == clientListPerm_.end() ) | 
|---|
 | 318 |     { | 
|---|
 | 319 |       assert(!this->bActive_); | 
|---|
 | 320 |       return; | 
|---|
 | 321 |     } | 
|---|
 | 322 |     clientListTemp_.erase(clientListTemp_.find(clientID)); | 
|---|
 | 323 |     if( clientListTemp_.find(clientID) != clientListTemp_.end() ) | 
|---|
 | 324 |       clientListPerm_.erase(clientListPerm_.find(clientID)); | 
|---|
 | 325 |   } | 
|---|
 | 326 |  | 
|---|
 | 327 |  | 
|---|
 | 328 | }//namespace network | 
|---|