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