Changeset 3370 for code/trunk/src/core/Game.cc
- Timestamp:
- Jul 30, 2009, 2:10:44 PM (16 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
/code/branches/resource (added) merged: 3328,3336-3340,3342-3350,3352-3366
- Property svn:mergeinfo changed
-
code/trunk/src/core/Game.cc
r3323 r3370 40 40 #include "util/Debug.h" 41 41 #include "util/Exception.h" 42 #include "util/ScopeGuard.h" 42 43 #include "util/Sleep.h" 43 44 #include "util/SubString.h" … … 48 49 #include "CoreIncludes.h" 49 50 #include "ConfigValueIncludes.h" 51 #include "GameMode.h" 50 52 #include "GameState.h" 51 53 … … 59 61 SetConsoleCommandShortcutExternAlias(stop_game, "exit"); 60 62 61 std::map<std::string, Game ::GameStateInfo> Game::gameStateDeclarations_s;62 Game* Game::singleton Ref_s = 0;63 std::map<std::string, GameStateInfo> Game::gameStateDeclarations_s; 64 Game* Game::singletonPtr_s = 0; 63 65 64 66 … … 69 71 struct GameStateTreeNode 70 72 { 71 GameState* state_;73 std::string name_; 72 74 weak_ptr<GameStateTreeNode> parent_; 73 75 std::vector<shared_ptr<GameStateTreeNode> > children_; … … 112 114 Game::Game(const std::string& cmdLine) 113 115 { 114 if (singletonRef_s != 0)115 {116 COUT(0) << "Error: The Game singleton cannot be recreated! Shutting down." << std::endl;117 abort();118 }119 singletonRef_s = this;120 121 116 this->bAbort_ = false; 122 117 bChangingState_ = false; 123 118 119 #ifdef ORXONOX_PLATFORM_WINDOWS 120 minimumSleepTime_ = 1000/*us*/; 121 #else 122 minimumSleepTime_ = 0/*us*/; 123 #endif 124 124 125 // Create an empty root state 125 declareGameState<GameState>("GameState", "emptyRootGameState", true, false); 126 127 // reset statistics 128 this->statisticsStartTime_ = 0; 129 this->statisticsTickTimes_.clear(); 130 this->periodTickTime_ = 0; 131 this->periodTime_ = 0; 132 this->avgFPS_ = 0.0f; 133 this->avgTickTime_ = 0.0f; 126 this->declareGameState<GameState>("GameState", "emptyRootGameState", true, false); 134 127 135 128 // Set up a basic clock to keep time 136 this->gameClock_ = new Clock();129 this->gameClock_.reset(new Clock()); 137 130 138 131 // Create the Core 139 this->core_ = new Core(cmdLine);140 141 // After the core has been created, we can safely instantiate the GameStates 132 this->core_.reset(new Core(cmdLine)); 133 134 // After the core has been created, we can safely instantiate the GameStates that don't require graphics 142 135 for (std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.begin(); 143 136 it != gameStateDeclarations_s.end(); ++it) 144 137 { 145 // Only create the states appropriate for the game mode 146 //if (GameMode::showsGraphics || !it->second.bGraphicsMode) 147 GameStateConstrParams params = { it->second.stateName, it->second.bIgnoreTickTime }; 148 gameStates_[getLowercase(it->second.stateName)] = GameStateFactory::fabricate(it->second.className, params); 138 if (!it->second.bGraphicsMode) 139 constructedStates_[it->second.stateName] = GameStateFactory::fabricate(it->second); 149 140 } 150 141 151 142 // The empty root state is ALWAYS loaded! 152 143 this->rootStateNode_ = shared_ptr<GameStateTreeNode>(new GameStateTreeNode()); 153 this->rootStateNode_-> state_ = getState("emptyRootGameState");154 this-> activeStateNode_ = this->rootStateNode_;155 this-> activeStates_.push_back(this->rootStateNode_->state_);144 this->rootStateNode_->name_ = "emptyRootGameState"; 145 this->loadedTopStateNode_ = this->rootStateNode_; 146 this->loadedStates_.push_back(this->getState(rootStateNode_->name_)); 156 147 157 148 // Do this after the Core creation! 158 this->configuration_ = new GameConfiguration();149 this->configuration_.reset(new GameConfiguration()); 159 150 } 160 151 161 152 /** 162 153 @brief 154 All destruction code is handled by scoped_ptrs and SimpleScopeGuards. 163 155 */ 164 156 Game::~Game() 165 157 { 166 // Destroy the configuration helper class instance167 delete this->configuration_;168 169 // Destroy the GameStates (note that the nodes still point to them, but doesn't matter)170 for (std::map<std::string, GameState*>::const_iterator it = gameStates_.begin();171 it != gameStates_.end(); ++it)172 delete it->second;173 174 // Destroy the Core and with it almost everything175 delete this->core_;176 delete this->gameClock_;177 178 // Take care of the GameStateFactories179 GameStateFactory::destroyFactories();180 181 // Don't assign singletonRef_s with NULL! Recreation is not supported182 158 } 183 159 … … 195 171 COUT(0) << "Warning: Starting game without requesting GameState. This automatically terminates the program." << std::endl; 196 172 173 // reset statistics 174 this->statisticsStartTime_ = 0; 175 this->statisticsTickTimes_.clear(); 176 this->periodTickTime_ = 0; 177 this->periodTime_ = 0; 178 this->avgFPS_ = 0.0f; 179 this->avgTickTime_ = 0.0f; 180 this->excessSleepTime_ = 0; 181 197 182 // START GAME 198 183 // first delta time should be about 0 seconds … … 201 186 StatisticsTickInfo tickInfo = {0, 0}; 202 187 statisticsTickTimes_.push_back(tickInfo); 203 while (!this->bAbort_ && (!this->activeStates_.empty() || this->requestedStateNodes_.size() > 0)) 204 { 205 uint64_t currentTime = this->gameClock_->getRealMicroseconds(); 206 207 uint64_t nextTickTime = statisticsTickTimes_.back().tickTime + static_cast<uint64_t>(1000000.0f / configuration_->fpsLimit_); 208 if (currentTime < nextTickTime) 209 { 210 usleep(nextTickTime - currentTime); 211 continue; 212 } 188 while (!this->bAbort_ && (!this->loadedStates_.empty() || this->requestedStateNodes_.size() > 0)) 189 { 190 // Generate the dt 213 191 this->gameClock_->capture(); 214 192 215 // S TATISTICS216 StatisticsTickInfo tickInfo = { currentTime, 0};193 // Statistics init 194 StatisticsTickInfo tickInfo = {gameClock_->getMicroseconds(), 0}; 217 195 statisticsTickTimes_.push_back(tickInfo); 218 196 this->periodTime_ += this->gameClock_->getDeltaTimeMicroseconds(); 219 197 220 // UPDATE STATE STACK 221 while (this->requestedStateNodes_.size() > 0) 222 { 223 shared_ptr<GameStateTreeNode> requestedStateNode = this->requestedStateNodes_.front(); 224 assert(this->activeStateNode_); 225 if (!this->activeStateNode_->parent_.expired() && requestedStateNode == this->activeStateNode_->parent_.lock()) 226 this->unloadState(this->activeStateNode_->state_); 227 else // has to be child 228 { 229 try 230 { 231 this->loadState(requestedStateNode->state_); 232 } 233 catch (const std::exception& ex) 234 { 235 COUT(1) << "Error: Loading GameState '" << requestedStateNode->state_->getName() << "' failed: " << ex.what() << std::endl; 236 // All scheduled operations have now been rendered inert --> flush them and issue a warning 237 if (this->requestedStateNodes_.size() > 1) 238 COUT(1) << "All " << this->requestedStateNodes_.size() - 1 << " scheduled transitions have been ignored." << std::endl; 239 this->requestedStateNodes_.clear(); 240 break; 241 } 242 } 243 this->activeStateNode_ = requestedStateNode; 244 this->requestedStateNodes_.erase(this->requestedStateNodes_.begin()); 245 } 246 247 // UPDATE, Core first 248 bool threwException = false; 249 try 250 { 251 this->core_->update(*this->gameClock_); 252 } 253 catch (const std::exception& ex) 254 { 255 threwException = true; 256 COUT(0) << "Exception while ticking the Core: " << ex.what() << std::endl; 257 } 258 catch (...) 259 { 260 threwException = true; 261 } 262 if (threwException) 263 { 264 COUT(0) << "An exception occured while ticking the Core. This should really never happen!" << std::endl; 265 COUT(0) << "Closing the program." << std::endl; 198 // Update the GameState stack if required 199 this->updateGameStateStack(); 200 201 // Core preUpdate (doesn't throw) 202 if (!this->core_->preUpdate(*this->gameClock_)) 203 { 266 204 this->stop(); 267 205 break; 268 206 } 269 207 270 // UPDATE, GameStates bottom to top in the stack 271 // Note: The first element is the empty root state, which doesn't need ticking 272 for (std::vector<GameState*>::const_iterator it = this->activeStates_.begin() + 1; 273 it != this->activeStates_.end(); ++it) 274 { 275 bool threwException = false; 208 // Update the GameStates bottom up in the stack 209 this->updateGameStates(); 210 211 // Core postUpdate (doesn't throw) 212 if (!this->core_->postUpdate(*this->gameClock_)) 213 { 214 this->stop(); 215 break; 216 } 217 218 // Evaluate statistics 219 this->updateStatistics(); 220 221 // Limit framerate 222 this->updateFPSLimiter(); 223 } 224 225 // UNLOAD all remaining states 226 while (this->loadedStates_.size() > 1) 227 this->unloadState(this->loadedStates_.back()->getName()); 228 this->loadedTopStateNode_ = this->rootStateNode_; 229 this->requestedStateNodes_.clear(); 230 } 231 232 void Game::updateGameStateStack() 233 { 234 while (this->requestedStateNodes_.size() > 0) 235 { 236 shared_ptr<GameStateTreeNode> requestedStateNode = this->requestedStateNodes_.front(); 237 assert(this->loadedTopStateNode_); 238 if (!this->loadedTopStateNode_->parent_.expired() && requestedStateNode == this->loadedTopStateNode_->parent_.lock()) 239 this->unloadState(loadedTopStateNode_->name_); 240 else // has to be child 241 { 276 242 try 277 243 { 278 // Add tick time for most of the states 279 uint64_t timeBeforeTick; 280 if (!(*it)->ignoreTickTime()) 281 timeBeforeTick = this->gameClock_->getRealMicroseconds(); 282 (*it)->update(*this->gameClock_); 283 if (!(*it)->ignoreTickTime()) 284 this->addTickTime(static_cast<uint32_t>(this->gameClock_->getRealMicroseconds() - timeBeforeTick)); 244 this->loadState(requestedStateNode->name_); 285 245 } 286 246 catch (const std::exception& ex) 287 247 { 288 threwException = true; 289 COUT(0) << "Exception while ticking: " << ex.what() << std::endl; 290 } 291 catch (...) 292 { 293 threwException = true; 294 } 295 if (threwException) 296 { 297 COUT(1) << "An exception occured while ticking GameState '" << (*it)->getName() << "'. This should really never happen!" << std::endl; 298 COUT(1) << "Unloading all GameStates depending on the one that crashed." << std::endl; 299 if ((*it)->getParent() != NULL) 300 this->requestState((*it)->getParent()->getName()); 301 else 302 this->stop(); 248 COUT(1) << "Error: Loading GameState '" << requestedStateNode->name_ << "' failed: " << ex.what() << std::endl; 249 // All scheduled operations have now been rendered inert --> flush them and issue a warning 250 if (this->requestedStateNodes_.size() > 1) 251 COUT(1) << "All " << this->requestedStateNodes_.size() - 1 << " scheduled transitions have been ignored." << std::endl; 252 this->requestedStateNodes_.clear(); 303 253 break; 304 254 } 305 306 } 307 308 // STATISTICS 309 if (this->periodTime_ > this->configuration_->statisticsRefreshCycle_) 310 { 311 std::list<StatisticsTickInfo>::iterator it = this->statisticsTickTimes_.begin(); 312 assert(it != this->statisticsTickTimes_.end()); 313 int64_t lastTime = currentTime - this->configuration_->statisticsAvgLength_; 314 if (static_cast<int64_t>(it->tickTime) < lastTime) 255 } 256 this->loadedTopStateNode_ = requestedStateNode; 257 this->requestedStateNodes_.erase(this->requestedStateNodes_.begin()); 258 } 259 } 260 261 void Game::updateGameStates() 262 { 263 // Note: The first element is the empty root state, which doesn't need ticking 264 for (GameStateVector::const_iterator it = this->loadedStates_.begin() + 1; 265 it != this->loadedStates_.end(); ++it) 266 { 267 std::string exceptionMessage; 268 try 269 { 270 // Add tick time for most of the states 271 uint64_t timeBeforeTick; 272 if ((*it)->getInfo().bIgnoreTickTime) 273 timeBeforeTick = this->gameClock_->getRealMicroseconds(); 274 (*it)->update(*this->gameClock_); 275 if ((*it)->getInfo().bIgnoreTickTime) 276 this->subtractTickTime(static_cast<int32_t>(this->gameClock_->getRealMicroseconds() - timeBeforeTick)); 277 } 278 catch (const std::exception& ex) 279 { exceptionMessage = ex.what(); } 280 catch (...) 281 { exceptionMessage = "Unknown exception"; } 282 if (!exceptionMessage.empty()) 283 { 284 COUT(1) << "An exception occurred while updating '" << (*it)->getName() << "': " << exceptionMessage << std::endl; 285 COUT(1) << "This should really never happen!" << std::endl; 286 COUT(1) << "Unloading all GameStates depending on the one that crashed." << std::endl; 287 shared_ptr<GameStateTreeNode> current = this->loadedTopStateNode_; 288 while (current->name_ != (*it)->getName() && current) 289 current = current->parent_.lock(); 290 if (current && current->parent_.lock()) 291 this->requestState(current->parent_.lock()->name_); 292 else 293 this->stop(); 294 break; 295 } 296 } 297 } 298 299 void Game::updateStatistics() 300 { 301 // Add the tick time of this frame (rendering time has already been subtracted) 302 uint64_t currentTime = gameClock_->getMicroseconds(); 303 uint64_t currentRealTime = gameClock_->getRealMicroseconds(); 304 this->statisticsTickTimes_.back().tickLength += currentRealTime - currentTime; 305 this->periodTickTime_ += currentRealTime - currentTime; 306 if (this->periodTime_ > this->configuration_->statisticsRefreshCycle_) 307 { 308 std::list<StatisticsTickInfo>::iterator it = this->statisticsTickTimes_.begin(); 309 assert(it != this->statisticsTickTimes_.end()); 310 int64_t lastTime = currentTime - this->configuration_->statisticsAvgLength_; 311 if (static_cast<int64_t>(it->tickTime) < lastTime) 312 { 313 do 315 314 { 316 do 317 { 318 assert(this->periodTickTime_ >= it->tickLength); 319 this->periodTickTime_ -= it->tickLength; 320 ++it; 321 assert(it != this->statisticsTickTimes_.end()); 322 } while (static_cast<int64_t>(it->tickTime) < lastTime); 323 this->statisticsTickTimes_.erase(this->statisticsTickTimes_.begin(), it); 324 } 325 326 uint32_t framesPerPeriod = this->statisticsTickTimes_.size(); 327 this->avgFPS_ = static_cast<float>(framesPerPeriod) / (currentTime - this->statisticsTickTimes_.front().tickTime) * 1000000.0f; 328 this->avgTickTime_ = static_cast<float>(this->periodTickTime_) / framesPerPeriod / 1000.0f; 329 330 this->periodTime_ -= this->configuration_->statisticsRefreshCycle_; 331 } 332 } 333 334 // UNLOAD all remaining states 335 while (this->activeStates_.size() > 1) 336 this->unloadState(this->activeStates_.back()); 337 this->activeStateNode_ = this->rootStateNode_; 338 this->requestedStateNodes_.clear(); 315 assert(this->periodTickTime_ >= it->tickLength); 316 this->periodTickTime_ -= it->tickLength; 317 ++it; 318 assert(it != this->statisticsTickTimes_.end()); 319 } while (static_cast<int64_t>(it->tickTime) < lastTime); 320 this->statisticsTickTimes_.erase(this->statisticsTickTimes_.begin(), it); 321 } 322 323 uint32_t framesPerPeriod = this->statisticsTickTimes_.size(); 324 this->avgFPS_ = static_cast<float>(framesPerPeriod) / (currentTime - this->statisticsTickTimes_.front().tickTime) * 1000000.0f; 325 this->avgTickTime_ = static_cast<float>(this->periodTickTime_) / framesPerPeriod / 1000.0f; 326 327 this->periodTime_ -= this->configuration_->statisticsRefreshCycle_; 328 } 329 } 330 331 void Game::updateFPSLimiter() 332 { 333 // Why configuration_->fpsLimit_ - 1? No idea, but otherwise the fps rate is always (from 10 to 200!) one frame too high 334 uint32_t nextTime = gameClock_->getMicroseconds() - excessSleepTime_ + static_cast<uint32_t>(1000000.0f / (configuration_->fpsLimit_ - 1)); 335 uint64_t currentRealTime = gameClock_->getRealMicroseconds(); 336 while (currentRealTime < nextTime - minimumSleepTime_) 337 { 338 usleep(nextTime - currentRealTime); 339 currentRealTime = gameClock_->getRealMicroseconds(); 340 } 341 // Integrate excess to avoid steady state error 342 excessSleepTime_ = currentRealTime - nextTime; 343 // Anti windup 344 if (excessSleepTime_ > 50000) // 20ms is about the maximum time Windows would sleep for too long 345 excessSleepTime_ = 50000; 339 346 } 340 347 … … 344 351 } 345 352 346 void Game:: addTickTime(uint32_t length)353 void Game::subtractTickTime(int32_t length) 347 354 { 348 355 assert(!this->statisticsTickTimes_.empty()); 349 this->statisticsTickTimes_.back().tickLength += length;350 this->periodTickTime_ +=length;356 this->statisticsTickTimes_.back().tickLength -= length; 357 this->periodTickTime_ -= length; 351 358 } 352 359 … … 356 363 void Game::requestState(const std::string& name) 357 364 { 358 GameState* state = this->getState(name); 359 if (state == NULL) 365 if (!this->checkState(name)) 366 { 367 COUT(2) << "Warning: GameState named '" << name << "' doesn't exist!" << std::endl; 360 368 return; 361 362 //if (this->bChangingState_) 363 //{ 364 // COUT(2) << "Warning: Requesting GameStates while loading/unloading a GameState is illegal! Ignoring." << std::endl; 365 // return; 366 //} 369 } 370 371 if (this->bChangingState_) 372 { 373 COUT(2) << "Warning: Requesting GameStates while loading/unloading a GameState is illegal! Ignoring." << std::endl; 374 return; 375 } 367 376 368 377 shared_ptr<GameStateTreeNode> lastRequestedNode; 369 378 if (this->requestedStateNodes_.empty()) 370 lastRequestedNode = this-> activeStateNode_;379 lastRequestedNode = this->loadedTopStateNode_; 371 380 else 372 381 lastRequestedNode = this->requestedStateNodes_.back(); 373 if ( state == lastRequestedNode->state_)382 if (name == lastRequestedNode->name_) 374 383 { 375 384 COUT(2) << "Warning: Requesting the currently active state! Ignoring." << std::endl; … … 381 390 for (unsigned int i = 0; i < lastRequestedNode->children_.size(); ++i) 382 391 { 383 if (lastRequestedNode->children_[i]-> state_ == state)392 if (lastRequestedNode->children_[i]->name_ == name) 384 393 { 385 394 requestedNodes.push_back(lastRequestedNode->children_[i]); … … 394 403 while (currentNode != NULL) 395 404 { 396 if (currentNode-> state_ == state)405 if (currentNode->name_ == name) 397 406 break; 398 407 currentNode = currentNode->parent_.lock(); … … 418 427 shared_ptr<GameStateTreeNode> lastRequestedNode; 419 428 if (this->requestedStateNodes_.empty()) 420 lastRequestedNode = this-> activeStateNode_;429 lastRequestedNode = this->loadedTopStateNode_; 421 430 else 422 431 lastRequestedNode = this->requestedStateNodes_.back(); 423 432 if (lastRequestedNode != this->rootStateNode_) 424 this->requestState(lastRequestedNode->parent_.lock()-> state_->getName());433 this->requestState(lastRequestedNode->parent_.lock()->name_); 425 434 else 426 435 COUT(2) << "Warning: Can't pop the internal dummy root GameState" << std::endl; 427 436 } 428 437 429 GameState*Game::getState(const std::string& name)430 { 431 std::map<std::string, GameState*>::const_iterator it = gameStates_.find(getLowercase(name));432 if (it != gameStates_.end())438 shared_ptr<GameState> Game::getState(const std::string& name) 439 { 440 GameStateMap::const_iterator it = constructedStates_.find(name); 441 if (it != constructedStates_.end()) 433 442 return it->second; 434 443 else 435 444 { 436 COUT(1) << "Error: Could not find GameState '" << name << "'. Ignoring." << std::endl; 437 return 0; 445 std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.find(name); 446 if (it != gameStateDeclarations_s.end()) 447 COUT(1) << "Error: GameState '" << name << "' has not yet been loaded." << std::endl; 448 else 449 COUT(1) << "Error: Could not find GameState '" << name << "'." << std::endl; 450 return shared_ptr<GameState>(); 438 451 } 439 452 } … … 461 474 std::string newStateName = it->first; 462 475 unsigned newLevel = it->second + 1; // empty root is 0 463 GameState* newState = this->getState(newStateName); 464 if (!newState) 476 if (!this->checkState(newStateName)) 465 477 ThrowException(GameState, "GameState with name '" << newStateName << "' not found!"); 466 if (newState == this->rootStateNode_->state_)478 if (newStateName == this->rootStateNode_->name_) 467 479 ThrowException(GameState, "You shouldn't use 'emptyRootGameState' in the hierarchy..."); 468 480 shared_ptr<GameStateTreeNode> newNode(new GameStateTreeNode); 469 newNode-> state_ = newState;481 newNode->name_ = newStateName; 470 482 471 483 if (newLevel <= currentLevel) … … 480 492 newNode->parent_ = currentNode; 481 493 currentNode->children_.push_back(newNode); 482 currentNode->state_->addChild(newNode->state_);483 494 } 484 495 else … … 491 502 /*** Internal ***/ 492 503 493 void Game::loadState(GameState* state) 504 void Game::loadGraphics() 505 { 506 if (!GameMode::bShowsGraphics_s) 507 { 508 core_->loadGraphics(); 509 Loki::ScopeGuard graphicsUnloader = Loki::MakeObjGuard(*this, &Game::unloadGraphics); 510 GameMode::bShowsGraphics_s = true; 511 512 // Construct all the GameStates that require graphics 513 for (std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.begin(); 514 it != gameStateDeclarations_s.end(); ++it) 515 { 516 if (it->second.bGraphicsMode) 517 { 518 // Game state loading failure is serious --> don't catch 519 shared_ptr<GameState> gameState = GameStateFactory::fabricate(it->second); 520 if (!constructedStates_.insert(std::make_pair( 521 it->second.stateName, gameState)).second) 522 assert(false); // GameState was already created! 523 } 524 } 525 graphicsUnloader.Dismiss(); 526 } 527 } 528 529 void Game::unloadGraphics() 530 { 531 if (GameMode::bShowsGraphics_s) 532 { 533 // Destroy all the GameStates that require graphics 534 for (GameStateMap::iterator it = constructedStates_.begin(); it != constructedStates_.end();) 535 { 536 if (it->second->getInfo().bGraphicsMode) 537 constructedStates_.erase(it++); 538 else 539 ++it; 540 } 541 542 core_->unloadGraphics(); 543 GameMode::bShowsGraphics_s = false; 544 } 545 } 546 547 bool Game::checkState(const std::string& name) const 548 { 549 std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.find(name); 550 if (it == gameStateDeclarations_s.end()) 551 return false; 552 else 553 return true; 554 } 555 556 void Game::loadState(const std::string& name) 494 557 { 495 558 this->bChangingState_ = true; 559 LOKI_ON_BLOCK_EXIT_OBJ(*this, &Game::resetChangingState); 560 561 // If state requires graphics, load it 562 Loki::ScopeGuard graphicsUnloader = Loki::MakeObjGuard(*this, &Game::unloadGraphics); 563 if (gameStateDeclarations_s[name].bGraphicsMode && !GameMode::showsGraphics()) 564 this->loadGraphics(); 565 else 566 graphicsUnloader.Dismiss(); 567 568 shared_ptr<GameState> state = this->getState(name); 496 569 state->activate(); 497 if (!this-> activeStates_.empty())498 this-> activeStates_.back()->activity_.topState = false;499 this-> activeStates_.push_back(state);570 if (!this->loadedStates_.empty()) 571 this->loadedStates_.back()->activity_.topState = false; 572 this->loadedStates_.push_back(state); 500 573 state->activity_.topState = true; 574 575 graphicsUnloader.Dismiss(); 576 } 577 578 void Game::unloadState(const std::string& name) 579 { 580 this->bChangingState_ = true; 581 try 582 { 583 shared_ptr<GameState> state = this->getState(name); 584 state->activity_.topState = false; 585 this->loadedStates_.pop_back(); 586 if (!this->loadedStates_.empty()) 587 this->loadedStates_.back()->activity_.topState = true; 588 state->deactivate(); 589 } 590 catch (const std::exception& ex) 591 { 592 COUT(2) << "Warning: Unloading GameState '" << name << "' threw an exception: " << ex.what() << std::endl; 593 COUT(2) << " There might be potential resource leaks involved! To avoid this, improve exception-safety." << std::endl; 594 } 595 // Check if graphics is still required 596 bool graphicsRequired = false; 597 for (unsigned i = 0; i < loadedStates_.size(); ++i) 598 graphicsRequired |= loadedStates_[i]->getInfo().bGraphicsMode; 599 if (!graphicsRequired) 600 this->unloadGraphics(); 501 601 this->bChangingState_ = false; 502 602 } 503 603 504 void Game::unloadState(orxonox::GameState* state) 505 { 506 this->bChangingState_ = true; 507 state->activity_.topState = false; 508 this->activeStates_.pop_back(); 509 if (!this->activeStates_.empty()) 510 this->activeStates_.back()->activity_.topState = true; 511 try 512 { 513 state->deactivate(); 514 } 515 catch (const std::exception& ex) 516 { 517 COUT(2) << "Warning: Unloading GameState '" << state->getName() << "' threw an exception: " << ex.what() << std::endl; 518 COUT(2) << " There might be potential resource leaks involved! To avoid this, improve exception-safety." << std::endl; 519 } 520 this->bChangingState_ = false; 521 } 522 523 std::map<std::string, Game::GameStateFactory*> Game::GameStateFactory::factories_s; 524 525 /*static*/ GameState* Game::GameStateFactory::fabricate(const std::string& className, const GameStateConstrParams& params) 526 { 527 std::map<std::string, GameStateFactory*>::const_iterator it = factories_s.find(className); 604 std::map<std::string, shared_ptr<Game::GameStateFactory> > Game::GameStateFactory::factories_s; 605 606 /*static*/ shared_ptr<GameState> Game::GameStateFactory::fabricate(const GameStateInfo& info) 607 { 608 std::map<std::string, shared_ptr<Game::GameStateFactory> >::const_iterator it = factories_s.find(info.className); 528 609 assert(it != factories_s.end()); 529 return it->second->fabricate(params); 530 } 531 532 /*static*/ void Game::GameStateFactory::destroyFactories() 533 { 534 for (std::map<std::string, GameStateFactory*>::const_iterator it = factories_s.begin(); it != factories_s.end(); ++it) 535 delete it->second; 536 factories_s.clear(); 610 return it->second->fabricateInternal(info); 537 611 } 538 612 }
Note: See TracChangeset
for help on using the changeset viewer.