Changeset 3238 for code/branches/core4/src/core
- Timestamp:
- Jun 28, 2009, 1:47:57 PM (16 years ago)
- Location:
- code/branches/core4/src/core
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/core4/src/core/Game.cc
r3196 r3238 54 54 using boost::weak_ptr; 55 55 56 std::map<std::string, GameState*> Game::allStates_s; 57 Game* Game::singletonRef_s = 0; 58 56 59 static void stop_game() 57 60 { Game::getInstance().stop(); } 58 61 SetConsoleCommandShortcutExternAlias(stop_game, "exit"); 62 // Add an empty gamestate that serves as internal root state 63 AddGameState(GameState, "emptyRootGameState"); 59 64 60 65 struct _CoreExport GameStateTreeNode … … 64 69 std::vector<shared_ptr<GameStateTreeNode> > children_; 65 70 }; 66 67 std::map<std::string, GameState*> Game::allStates_s;68 Game* Game::singletonRef_s = 0;69 71 70 72 /** … … 77 79 singletonRef_s = this; 78 80 79 this->abort_ = false; 81 this->bAbort_ = false; 82 bChangingState_ = false; 83 // The empty root state is ALWAYS loaded! 84 this->rootStateNode_ = shared_ptr<GameStateTreeNode>(new GameStateTreeNode()); 85 this->rootStateNode_->state_ = getState("emptyRootGameState"); 86 this->activeStateNode_ = this->rootStateNode_; 87 this->activeStates_.push_back(this->rootStateNode_->state_); 80 88 81 89 // reset statistics … … 86 94 this->avgFPS_ = 0.0f; 87 95 this->avgTickTime_ = 0.0f; 88 89 96 90 97 // Set up a basic clock to keep time … … 147 154 void Game::run() 148 155 { 149 // Always start with the ROOT state 150 this->requestedStateNodes_.push_back(this->rootStateNode_); 151 this->activeStateNode_ = this->rootStateNode_; 152 this->loadState(this->rootStateNode_->state_); 156 if (this->requestedStateNodes_.empty()) 157 COUT(0) << "Warning: Starting game without requesting GameState. This automatically terminates the program." << std::endl; 153 158 154 159 // START GAME 155 160 this->gameClock_->capture(); // first delta time should be about 0 seconds 156 while (!this-> abort_ && !this->activeStates_.empty())161 while (!this->bAbort_ && (!this->activeStates_.empty() || this->requestedStateNodes_.size() > 0)) 157 162 { 158 163 this->gameClock_->capture(); … … 165 170 166 171 // UPDATE STATE STACK 167 while (this->requestedStateNodes_.size() > 1)168 { 169 // Note: this->requestedStateNodes_.front() is the currently active state node170 std::vector<shared_ptr<GameStateTreeNode> >::iterator it = this->requestedStateNodes_.begin() + 1;171 if ( *it== this->activeStateNode_->parent_.lock())172 while (this->requestedStateNodes_.size() > 0) 173 { 174 shared_ptr<GameStateTreeNode> requestedStateNode = this->requestedStateNodes_.front(); 175 assert(this->activeStateNode_); 176 if (!this->activeStateNode_->parent_.expired() && requestedStateNode == this->activeStateNode_->parent_.lock()) 172 177 this->unloadState(this->activeStateNode_->state_); 173 178 else // has to be child 174 this->loadState((*it)->state_); 175 this->activeStateNode_ = *it; 179 { 180 try 181 { 182 this->loadState(requestedStateNode->state_); 183 } 184 catch (const std::exception& ex) 185 { 186 COUT(1) << "Error: Loading GameState '" << requestedStateNode->state_->getName() << "' failed: " << ex.what() << std::endl; 187 // All scheduled operations have now been rendered inert --> flush them and issue a warning 188 if (this->requestedStateNodes_.size() > 1) 189 COUT(1) << "All " << this->requestedStateNodes_.size() - 1 << " scheduled transitions have been ignored." << std::endl; 190 this->requestedStateNodes_.clear(); 191 break; 192 } 193 } 194 this->activeStateNode_ = requestedStateNode; 176 195 this->requestedStateNodes_.erase(this->requestedStateNodes_.begin()); 177 196 } 178 197 179 // UPDATE, bottom to top in the stack 180 this->core_->update(*this->gameClock_); 181 for (std::vector<GameState*>::const_iterator it = this->activeStates_.begin(); 198 // UPDATE, Core first 199 try 200 { 201 this->core_->update(*this->gameClock_); 202 } 203 catch (...) 204 { 205 COUT(0) << "An exception occured while ticking the Core. This should really never happen!" << std::endl; 206 COUT(0) << "Closing the program." << std::endl; 207 this->stop(); 208 break; 209 } 210 211 // UPDATE, GameStates bottom to top in the stack 212 // Note: The first element is the empty root state, which doesn't need ticking 213 for (std::vector<GameState*>::const_iterator it = this->activeStates_.begin() + 1; 182 214 it != this->activeStates_.end(); ++it) 183 215 { 184 // Add tick time for most of the states 185 uint64_t timeBeforeTick; 186 if ((*it)->getCountTickTime()) 187 timeBeforeTick = this->gameClock_->getRealMicroseconds(); 188 189 (*it)->update(*this->gameClock_); 190 191 if ((*it)->getCountTickTime()) 192 this->addTickTime(static_cast<uint32_t>(this->gameClock_->getRealMicroseconds() - timeBeforeTick)); 216 try 217 { 218 // Add tick time for most of the states 219 uint64_t timeBeforeTick; 220 if (!(*it)->ignoreTickTime()) 221 timeBeforeTick = this->gameClock_->getRealMicroseconds(); 222 (*it)->update(*this->gameClock_); 223 if (!(*it)->ignoreTickTime()) 224 this->addTickTime(static_cast<uint32_t>(this->gameClock_->getRealMicroseconds() - timeBeforeTick)); 225 } 226 catch (...) 227 { 228 COUT(1) << "An exception occured while ticking GameState '" << (*it)->getName() << "'. This should really never happen!" << std::endl; 229 COUT(1) << "Unloading all GameStates depending on the one that crashed." << std::endl; 230 if ((*it)->getParent() != NULL) 231 this->requestState((*it)->getParent()->getName()); 232 else 233 this->stop(); 234 break; 235 } 236 193 237 } 194 238 … … 203 247 do 204 248 { 205 assert(this->periodTickTime_ > it->tickLength);249 assert(this->periodTickTime_ >= it->tickLength); 206 250 this->periodTickTime_ -= it->tickLength; 207 251 ++it; … … 220 264 221 265 // UNLOAD all remaining states 222 while ( !this->activeStates_.empty())266 while (this->activeStates_.size() > 1) 223 267 this->unloadState(this->activeStates_.back()); 224 this->activeStateNode_ .reset();268 this->activeStateNode_ = this->rootStateNode_; 225 269 this->requestedStateNodes_.clear(); 226 270 } … … 228 272 void Game::stop() 229 273 { 230 this-> abort_ = true;274 this->bAbort_ = true; 231 275 } 232 276 … … 244 288 { 245 289 GameState* state = this->getState(name); 246 if (state == NULL || this->activeStateNode_ == NULL)290 if (state == NULL) 247 291 return; 248 292 249 shared_ptr<GameStateTreeNode> requestedNode; 250 251 // this->requestedStateNodes_.back() is the currently active state 252 shared_ptr<GameStateTreeNode> lastRequestedNode = this->requestedStateNodes_.back(); 253 254 // Already the active node? 293 //if (this->bChangingState_) 294 //{ 295 // COUT(2) << "Warning: Requesting GameStates while loading/unloading a GameState is illegal! Ignoring." << std::endl; 296 // return; 297 //} 298 299 shared_ptr<GameStateTreeNode> lastRequestedNode; 300 if (this->requestedStateNodes_.empty()) 301 lastRequestedNode = this->activeStateNode_; 302 else 303 lastRequestedNode = this->requestedStateNodes_.back(); 255 304 if (state == lastRequestedNode->state_) 256 305 { … … 260 309 261 310 // Check children first 311 shared_ptr<GameStateTreeNode> requestedNode; 262 312 for (unsigned int i = 0; i < lastRequestedNode->children_.size(); ++i) 263 313 { … … 293 343 void Game::popState() 294 344 { 295 if (this->activeStateNode_ != NULL && this->requestedStateNodes_.back()->parent_.lock()) 296 this->requestState(this->requestedStateNodes_.back()->parent_.lock()->state_->getName()); 297 else 298 COUT(2) << "Warning: Could not pop GameState. Ignoring." << std::endl; 345 shared_ptr<GameStateTreeNode> lastRequestedNode; 346 if (this->requestedStateNodes_.empty()) 347 lastRequestedNode = this->activeStateNode_; 348 else 349 lastRequestedNode = this->requestedStateNodes_.back(); 350 if (lastRequestedNode != this->rootStateNode_) 351 this->requestState(lastRequestedNode->parent_.lock()->state_->getName()); 352 else 353 COUT(2) << "Warning: Can't pop the internal dummy root GameState" << std::endl; 299 354 } 300 355 … … 325 380 while(pos < str.size() && str[pos] != ' ') 326 381 ++pos; 327 stateStrings.push_back(std::pair<std::string, unsigned>( 328 str.substr(startPos, pos - startPos), indentation)); 382 stateStrings.push_back(std::make_pair(str.substr(startPos, pos - startPos), indentation)); 329 383 } 330 384 unsigned int currentLevel = 0; 331 shared_ptr<GameStateTreeNode> currentNode ;385 shared_ptr<GameStateTreeNode> currentNode = this->rootStateNode_; 332 386 for (std::vector<std::pair<std::string, unsigned> >::const_iterator it = stateStrings.begin(); it != stateStrings.end(); ++it) 333 387 { 334 388 std::string newStateName = it->first; 335 unsigned newLevel = it->second ;389 unsigned newLevel = it->second + 1; // empty root is 0 336 390 GameState* newState = this->getState(newStateName); 337 391 if (!newState) 338 ThrowException(GameState, std::string("GameState with name '") + newStateName + "' not found!"); 339 if (newLevel == 0) 340 { 341 // root 342 if (this->rootStateNode_ != NULL) 343 ThrowException(GameState, "No two root GameStates are allowed!"); 344 shared_ptr<GameStateTreeNode> newNode(new GameStateTreeNode); 345 newNode->state_ = newState; 346 this->rootStateNode_ = newNode; 347 currentNode = this->rootStateNode_; 348 } 349 else if (currentNode) 350 { 351 shared_ptr<GameStateTreeNode> newNode(new GameStateTreeNode); 352 newNode->state_ = newState; 353 if (newLevel < currentLevel) 354 { 355 // Get down the hierarchy 356 do 357 currentNode = currentNode->parent_.lock(); 358 while (newLevel < --currentLevel); 359 } 360 if (newLevel == currentLevel) 361 { 362 // same level 363 newNode->parent_ = currentNode->parent_; 364 newNode->parent_.lock()->children_.push_back(newNode); 365 } 366 else if (newLevel == currentLevel + 1) 367 { 368 // child 369 newNode->parent_ = currentNode; 370 currentNode->children_.push_back(newNode); 371 } 372 else 373 ThrowException(GameState, "Indentation error while parsing the hierarchy."); 374 currentNode = newNode; 375 currentLevel = newLevel; 392 ThrowException(GameState, "GameState with name '" << newStateName << "' not found!"); 393 if (newState == this->rootStateNode_->state_) 394 ThrowException(GameState, "You shouldn't use 'emptyRootGameState' in the hierarchy..."); 395 shared_ptr<GameStateTreeNode> newNode(new GameStateTreeNode); 396 newNode->state_ = newState; 397 398 if (newLevel <= currentLevel) 399 { 400 do 401 currentNode = currentNode->parent_.lock(); 402 while (newLevel <= --currentLevel); 403 } 404 if (newLevel == currentLevel + 1) 405 { 406 // Add the child 407 newNode->parent_ = currentNode; 408 currentNode->children_.push_back(newNode); 409 currentNode->state_->addChild(newNode->state_); 376 410 } 377 411 else 378 {379 ThrowException(GameState, "No root GameState specified!");380 }412 ThrowException(GameState, "Indentation error while parsing the hierarchy."); 413 currentNode = newNode; 414 currentLevel = newLevel; 381 415 } 382 416 } … … 386 420 void Game::loadState(GameState* state) 387 421 { 422 this->bChangingState_ = true; 423 state->activate(); 388 424 if (!this->activeStates_.empty()) 389 425 this->activeStates_.back()->activity_.topState = false; 390 state->activate();426 this->activeStates_.push_back(state); 391 427 state->activity_.topState = true; 392 this-> activeStates_.push_back(state);428 this->bChangingState_ = false; 393 429 } 394 430 395 431 void Game::unloadState(orxonox::GameState* state) 396 432 { 433 this->bChangingState_ = true; 397 434 state->activity_.topState = false; 398 state->deactivate();399 435 this->activeStates_.pop_back(); 400 436 if (!this->activeStates_.empty()) 401 437 this->activeStates_.back()->activity_.topState = true; 438 try 439 { 440 state->deactivate(); 441 } 442 catch (const std::exception& ex) 443 { 444 COUT(2) << "Warning: Unloading GameState '" << state->getName() << "' threw an exception: " << ex.what() << std::endl; 445 COUT(2) << " There might be potential resource leaks involved! To avoid this, improve exception-safety." << std::endl; 446 } 447 this->bChangingState_ = false; 402 448 } 403 449 -
code/branches/core4/src/core/Game.h
r3196 r3238 118 118 Clock* gameClock_; 119 119 120 bool abort_; 120 bool bChangingState_; 121 bool bAbort_; 121 122 122 123 // variables for time statistics -
code/branches/core4/src/core/GameState.cc
r3196 r3238 45 45 Constructor only initialises variables and sets the name permanently. 46 46 */ 47 GameState::GameState(const std::string& name, bool countTickTime)47 GameState::GameState(const std::string& name, bool ignoreTickTime) 48 48 : name_(name) 49 , b CountTickTime_(countTickTime)49 , bIgnoreTickTime_(ignoreTickTime) 50 50 , parent_(0) 51 51 { -
code/branches/core4/src/core/GameState.h
r3196 r3238 77 77 78 78 public: 79 GameState(const std::string& name, bool countTicktime = true);79 GameState(const std::string& name, bool ignoreTicktime = false); 80 80 virtual ~GameState(); 81 81 … … 84 84 GameState* getParent() const { return this->parent_; } 85 85 86 bool getCountTickTime() const { return this->bCountTickTime_; }86 bool ignoreTickTime() const { return this->bIgnoreTickTime_; } 87 87 88 88 void addChild(GameState* state); … … 90 90 91 91 protected: 92 virtual void activate() = 0;93 virtual void deactivate() = 0;94 virtual void update(const Clock& time) = 0;92 virtual void activate() { } 93 virtual void deactivate() { } 94 virtual void update(const Clock& time) { } 95 95 96 96 private: … … 103 103 const std::string name_; 104 104 State activity_; 105 const bool b CountTickTime_;105 const bool bIgnoreTickTime_; 106 106 GameState* parent_; 107 107 std::map<std::string, GameState*> children_;
Note: See TracChangeset
for help on using the changeset viewer.