Changeset 3370 for code/trunk/src/core
- Timestamp:
- Jul 30, 2009, 2:10:44 PM (15 years ago)
- Location:
- code/trunk
- Files:
-
- 30 edited
- 4 copied
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/CMakeLists.txt
r3327 r3370 27 27 GameMode.cc 28 28 GameState.cc 29 GraphicsManager.cc 30 GUIManager.cc 29 31 Language.cc 30 32 LuaBind.cc … … 80 82 LINK_LIBRARIES 81 83 ${OGRE_LIBRARY} 84 ${Boost_FILESYSTEM_LIBRARY} 85 ${Boost_SYSTEM_LIBRARY} # Filesystem dependency 82 86 ${Boost_THREAD_LIBRARY} 83 ${Boost_ FILESYSTEM_LIBRARY}84 ${ Boost_SYSTEM_LIBRARY}85 ${ Boost_DATE_TIME_LIBRARY} # MSVC only87 ${Boost_DATE_TIME_LIBRARY} # Thread dependency 88 ${CEGUI_LIBRARY} 89 ${CEGUILUA_LIBRARY} 86 90 ${LUA_LIBRARIES} 87 91 cpptcl_orxonox 92 ogreceguirenderer_orxonox 88 93 ois_orxonox 89 94 tinyxml++_orxonox -
code/trunk/src/core/Clock.h
r3196 r3370 26 26 * 27 27 */ 28 29 /**30 @file31 @brief Declaration of the Core class.32 33 The Core class is a singleton, only used to configure some variables34 in the core through the config-file.35 */36 28 37 29 #ifndef _Clock_H__ -
code/trunk/src/core/ConfigFileManager.cc
r3301 r3370 42 42 const char* const DEFAULT_CONFIG_FILE = "default.ini"; 43 43 44 ConfigFileManager* ConfigFileManager::singleton Ref_s = 0;44 ConfigFileManager* ConfigFileManager::singletonPtr_s = 0; 45 45 46 46 SetConsoleCommandShortcutExtern(config).argumentCompleter(0, autocompletion::configvalueclasses()).argumentCompleter(1, autocompletion::configvalues()).argumentCompleter(2, autocompletion::configvalue()); … … 482 482 : mininmalFreeType_(ConfigFileType::numberOfReservedTypes) 483 483 { 484 assert(singletonRef_s == 0);485 singletonRef_s = this;486 484 } 487 485 … … 490 488 for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); ) 491 489 delete (it++)->second; 492 493 assert(singletonRef_s != 0);494 singletonRef_s = 0;495 490 } 496 491 -
code/trunk/src/core/ConfigFileManager.h
r3196 r3370 38 38 39 39 #include "util/OrxEnum.h" 40 #include "util/Singleton.h" 40 41 41 42 namespace orxonox … … 267 268 // ConfigFileManager // 268 269 /////////////////////// 269 class _CoreExport ConfigFileManager 270 { 270 class _CoreExport ConfigFileManager : public Singleton<ConfigFileManager> 271 { 272 friend class Singleton<ConfigFileManager>; 271 273 public: 272 274 ConfigFileManager(); … … 305 307 void updateConfigValues(ConfigFileType type); 306 308 307 static ConfigFileManager& getInstance() { assert(singletonRef_s); return *singletonRef_s; }308 309 309 private: 310 310 ConfigFileManager(const ConfigFileManager&); … … 315 315 unsigned int mininmalFreeType_; 316 316 317 static ConfigFileManager* singleton Ref_s;317 static ConfigFileManager* singletonPtr_s; 318 318 }; 319 319 } -
code/trunk/src/core/ConsoleCommandCompilation.cc
r3198 r3370 94 94 if (newline) 95 95 { 96 COUT(0) << text<< std::endl;96 COUT(0) << stripEnclosingBraces(text) << std::endl; 97 97 } 98 98 else 99 99 { 100 COUT(0) << text;100 COUT(0) << stripEnclosingBraces(text); 101 101 } 102 102 } -
code/trunk/src/core/Core.cc
r3323 r3370 41 41 #include <cstdio> 42 42 #include <boost/filesystem.hpp> 43 #include <OgreRenderWindow.h> 43 44 44 45 #ifdef ORXONOX_PLATFORM_WINDOWS … … 68 69 #include "CoreIncludes.h" 69 70 #include "Factory.h" 71 #include "GameMode.h" 72 #include "GraphicsManager.h" 73 #include "GUIManager.h" 70 74 #include "Identifier.h" 71 75 #include "Language.h" … … 74 78 #include "TclBind.h" 75 79 #include "TclThreadManager.h" 80 #include "input/InputManager.h" 76 81 77 82 namespace orxonox 78 83 { 79 84 //! Static pointer to the singleton 80 Core* Core::singleton Ref_s = 0;85 Core* Core::singletonPtr_s = 0; 81 86 82 87 SetCommandLineArgument(mediaPath, "").information("Path to the media/data files"); … … 134 139 .callback(this, &CoreConfiguration::debugLevelChanged); 135 140 136 SetConfigValue(language_, Language::get Language().defaultLanguage_)141 SetConfigValue(language_, Language::getInstance().defaultLanguage_) 137 142 .description("The language of the ingame text") 138 143 .callback(this, &CoreConfiguration::languageChanged); … … 141 146 .callback(this, &CoreConfiguration::initializeRandomNumberGenerator); 142 147 143 SetConfigValue(mediaPathString_, mediaPath_.string()) 144 .description("Relative path to the game data.") 145 .callback(this, &CoreConfiguration::mediaPathChanged); 148 // Only show this config value for development builds 149 if (Core::isDevelopmentRun()) 150 { 151 SetConfigValue(mediaPathString_, mediaPath_.string()) 152 .description("Relative path to the game data.") 153 .callback(this, &CoreConfiguration::mediaPathChanged); 154 } 146 155 } 147 156 … … 170 179 { 171 180 // Read the translation file after the language was configured 172 Language::get Language().readTranslatedLanguageFile();181 Language::getInstance().readTranslatedLanguageFile(); 173 182 } 174 183 … … 198 207 void tsetMediaPath(const std::string& path) 199 208 { 200 ModifyConfigValue(mediaPathString_, tset, path); 209 if (Core::isDevelopmentRun()) 210 { 211 ModifyConfigValue(mediaPathString_, tset, path); 212 } 213 else 214 { 215 // Manual 'config' value without the file entry 216 mediaPathString_ = path; 217 this->mediaPathChanged(); 218 } 201 219 } 202 220 … … 230 248 231 249 Core::Core(const std::string& cmdLine) 232 { 233 if (singletonRef_s != 0) 234 { 235 COUT(0) << "Error: The Core singleton cannot be recreated! Shutting down." << std::endl; 236 abort(); 237 } 238 Core::singletonRef_s = this; 239 240 // We need the variables very soon. But don't configure them yet! 241 this->configuration_ = new CoreConfiguration(); 242 250 // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands) 251 : identifierDestroyer_(Identifier::destroyAllIdentifiers) 252 // Cleanup guard for external console commands that don't belong to an Identifier 253 , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands) 254 , configuration_(new CoreConfiguration()) // Don't yet create config values! 255 , bDevRun_(false) 256 , bGraphicsLoaded_(false) 257 { 243 258 // Parse command line arguments first 244 259 CommandLine::parseCommandLine(cmdLine); … … 256 271 // create a signal handler (only active for linux) 257 272 // This call is placed as soon as possible, but after the directories are set 258 this->signalHandler_ = new SignalHandler();273 this->signalHandler_.reset(new SignalHandler()); 259 274 this->signalHandler_->doCatch(configuration_->executablePath_.string(), Core::getLogPathString() + "orxonox_crash.log"); 260 275 … … 275 290 276 291 // Manage ini files and set the default settings file (usually orxonox.ini) 277 this->configFileManager_ = new ConfigFileManager();292 this->configFileManager_.reset(new ConfigFileManager()); 278 293 this->configFileManager_->setFilename(ConfigFileType::Settings, 279 294 CommandLine::getValue("settingsFile").getString()); 280 295 281 296 // Required as well for the config values 282 this->languageInstance_ = new Language();297 this->languageInstance_.reset(new Language()); 283 298 284 299 // Do this soon after the ConfigFileManager has been created to open up the … … 287 302 288 303 // Create the lua interface 289 this->luaBind_ = new LuaBind();304 this->luaBind_.reset(new LuaBind()); 290 305 291 306 // initialise Tcl 292 this->tclBind_ = new TclBind(Core::getMediaPathString());293 this->tclThreadManager_ = new TclThreadManager(tclBind_->getTclInterpreter());307 this->tclBind_.reset(new TclBind(Core::getMediaPathString())); 308 this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter())); 294 309 295 310 // create a shell 296 this->shell_ = new Shell();311 this->shell_.reset(new Shell()); 297 312 298 313 // creates the class hierarchy for all classes with factories … … 301 316 302 317 /** 303 @brief Sets the bool to true to avoid static functions accessing a deleted object. 318 @brief 319 All destruction code is handled by scoped_ptrs and SimpleScopeGuards. 304 320 */ 305 321 Core::~Core() 306 322 { 307 delete this->shell_; 308 delete this->tclThreadManager_; 309 delete this->tclBind_; 310 delete this->luaBind_; 311 delete this->configuration_; 312 delete this->languageInstance_; 313 delete this->configFileManager_; 314 315 // Destroy command line arguments 316 CommandLine::destroyAllArguments(); 317 // Also delete external console command that don't belong to an Identifier 318 CommandExecutor::destroyExternalCommands(); 319 // Clean up class hierarchy stuff (identifiers, XMLPort, configValues, consoleCommand) 320 Identifier::destroyAllIdentifiers(); 321 322 delete this->signalHandler_; 323 324 // Don't assign singletonRef_s with NULL! Recreation is not supported 323 } 324 325 void Core::loadGraphics() 326 { 327 if (bGraphicsLoaded_) 328 return; 329 330 // Load OGRE including the render window 331 scoped_ptr<GraphicsManager> graphicsManager(new GraphicsManager()); 332 333 // The render window width and height are used to set up the mouse movement. 334 size_t windowHnd = 0; 335 graphicsManager->getRenderWindow()->getCustomAttribute("WINDOW", &windowHnd); 336 337 // Calls the InputManager which sets up the input devices. 338 scoped_ptr<InputManager> inputManager(new InputManager(windowHnd)); 339 340 // load the CEGUI interface 341 guiManager_.reset(new GUIManager(graphicsManager->getRenderWindow())); 342 343 // Dismiss scoped pointers 344 graphicsManager_.swap(graphicsManager); 345 inputManager_.swap(inputManager); 346 347 bGraphicsLoaded_ = true; 348 } 349 350 void Core::unloadGraphics() 351 { 352 if (!bGraphicsLoaded_) 353 return; 354 355 this->guiManager_.reset();; 356 this->inputManager_.reset();; 357 this->graphicsManager_.reset(); 358 359 bGraphicsLoaded_ = false; 325 360 } 326 361 … … 415 450 } 416 451 452 /*static*/ const boost::filesystem::path& Core::getRootPath() 453 { 454 return getInstance().configuration_->rootPath_; 455 } 456 /*static*/ std::string Core::getRootPathString() 457 { 458 return getInstance().configuration_->rootPath_.string() + '/'; 459 } 460 417 461 /** 418 462 @note … … 524 568 { 525 569 COUT(1) << "Running from the build tree." << std::endl; 526 Core:: isDevBuild_ = true;570 Core::bDevRun_ = true; 527 571 configuration_->mediaPath_ = ORXONOX_MEDIA_DEV_PATH; 528 572 configuration_->configPath_ = ORXONOX_CONFIG_DEV_PATH; … … 603 647 } 604 648 605 void Core::update(const Clock& time) 606 { 607 this->tclThreadManager_->update(time); 649 bool Core::preUpdate(const Clock& time) throw() 650 { 651 std::string exceptionMessage; 652 try 653 { 654 if (this->bGraphicsLoaded_) 655 { 656 // process input events 657 this->inputManager_->update(time); 658 // process gui events 659 this->guiManager_->update(time); 660 } 661 // process thread commands 662 this->tclThreadManager_->update(time); 663 } 664 catch (const std::exception& ex) 665 { exceptionMessage = ex.what(); } 666 catch (...) 667 { exceptionMessage = "Unknown exception"; } 668 if (!exceptionMessage.empty()) 669 { 670 COUT(0) << "An exception occurred in the Core preUpdate: " << exceptionMessage << std::endl; 671 COUT(0) << "This should really never happen! Closing the program." << std::endl; 672 return false; 673 } 674 return true; 675 } 676 677 bool Core::postUpdate(const Clock& time) throw() 678 { 679 std::string exceptionMessage; 680 try 681 { 682 if (this->bGraphicsLoaded_) 683 { 684 // Render (doesn't throw) 685 this->graphicsManager_->update(time); 686 } 687 } 688 catch (const std::exception& ex) 689 { exceptionMessage = ex.what(); } 690 catch (...) 691 { exceptionMessage = "Unknown exception"; } 692 if (!exceptionMessage.empty()) 693 { 694 COUT(0) << "An exception occurred in the Core postUpdate: " << exceptionMessage << std::endl; 695 COUT(0) << "This should really never happen! Closing the program." << std::endl; 696 return false; 697 } 698 return true; 608 699 } 609 700 } -
code/trunk/src/core/Core.h
r3323 r3370 43 43 44 44 #include <cassert> 45 #include <boost/scoped_ptr.hpp> 45 46 #include "util/OutputHandler.h" 47 #include "util/ScopeGuard.h" 48 #include "util/Singleton.h" 46 49 47 50 namespace orxonox 48 51 { 49 52 class CoreConfiguration; 53 using boost::scoped_ptr; 50 54 51 55 /** … … 55 59 The class provides information about the media, config and log path. 56 60 It determines those by the use of platform specific functions. 61 @remark 62 You should only create this singleton once because it destroys the identifiers! 57 63 */ 58 class _CoreExport Core 64 class _CoreExport Core : public Singleton<Core> 59 65 { 66 typedef Loki::ScopeGuardImpl0<void (*)()> SimpleScopeGuard; 67 friend class Singleton<Core>; 68 60 69 public: 61 70 /** … … 71 80 void setConfigValues(); 72 81 73 void update(const Clock& time); 82 bool preUpdate(const Clock& time) throw(); 83 bool postUpdate(const Clock& time) throw(); 74 84 75 static Core& getInstance() { assert(Core::singletonRef_s); return *Core::singletonRef_s; } 85 void loadGraphics(); 86 void unloadGraphics(); 76 87 77 88 static int getSoftDebugLevel(OutputHandler::OutputDevice device = OutputHandler::LD_All); … … 87 98 //! Returns the path to the log files as boost::filesystem::path 88 99 static const boost::filesystem::path& getLogPath(); 100 //! Returns the path to the root folder as boost::filesystem::path 101 static const boost::filesystem::path& getRootPath(); 89 102 //! Returns the path to the data files as std::string 90 103 static std::string getMediaPathString(); … … 93 106 //! Returns the path to the log files as std::string 94 107 static std::string getLogPathString(); 108 //! Returns the path to the root folder as std::string 109 static std::string getRootPathString(); 110 111 static bool isDevelopmentRun() { return getInstance().bDevRun_; } 95 112 96 113 private: … … 102 119 void setThreadAffinity(int limitToCPU); 103 120 104 // Singletons 105 ConfigFileManager* configFileManager_; 106 Language* languageInstance_; 107 LuaBind* luaBind_; 108 Shell* shell_; 109 SignalHandler* signalHandler_; 110 TclBind* tclBind_; 111 TclThreadManager* tclThreadManager_; 121 // Mind the order for the destruction! 122 scoped_ptr<SignalHandler> signalHandler_; 123 SimpleScopeGuard identifierDestroyer_; 124 SimpleScopeGuard consoleCommandDestroyer_; 125 scoped_ptr<ConfigFileManager> configFileManager_; 126 scoped_ptr<Language> languageInstance_; 127 scoped_ptr<CoreConfiguration> configuration_; 128 scoped_ptr<LuaBind> luaBind_; 129 scoped_ptr<TclBind> tclBind_; 130 scoped_ptr<TclThreadManager> tclThreadManager_; 131 scoped_ptr<Shell> shell_; 132 // graphical 133 scoped_ptr<GraphicsManager> graphicsManager_; //!< Interface to OGRE 134 scoped_ptr<InputManager> inputManager_; //!< Interface to OIS 135 scoped_ptr<GUIManager> guiManager_; //!< Interface to GUI 112 136 113 bool isDevBuild_; //!< True for builds in the build directory (not installed)114 CoreConfiguration* configuration_;137 bool bDevRun_; //!< True for runs in the build directory (not installed) 138 bool bGraphicsLoaded_; 115 139 116 static Core* singleton Ref_s;140 static Core* singletonPtr_s; 117 141 }; 118 142 } -
code/trunk/src/core/CorePrereqs.h
r3327 r3370 123 123 class FunctorMember; 124 124 class FunctorStatic; 125 class GraphicsManager; 126 class GUIManager; 125 127 class Identifier; 126 128 class IRC; … … 144 146 template <class T> 145 147 class ObjectListIterator; 148 class OgreWindowEventListener; 146 149 class OrxonoxClass; 147 150 class Shell; … … 167 170 // game states 168 171 class Game; 169 struct GameStateConstrParams;170 172 class GameState; 173 struct GameStateInfo; 171 174 struct GameStateTreeNode; 172 175 … … 220 223 } 221 224 225 // CEGUI 226 namespace CEGUI 227 { 228 class DefaultLogger; 229 class Logger; 230 class LuaScriptModule; 231 232 class OgreCEGUIRenderer; 233 class OgreCEGUIResourceProvider; 234 class OgreCEGUITexture; 235 } 236 237 // Lua 238 struct lua_State; 239 222 240 // TinyXML and TinyXML++ 223 241 class TiXmlString; -
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 } -
code/trunk/src/core/Game.h
r3323 r3370 44 44 #include <vector> 45 45 #include <boost/shared_ptr.hpp> 46 #include <boost/scoped_ptr.hpp> 46 47 #include <boost/preprocessor/cat.hpp> 47 48 48 49 #include "util/Debug.h" 49 #include "util/S tringUtils.h"50 #include "util/Singleton.h" 50 51 51 52 /** … … 60 61 { 61 62 class GameConfiguration; 63 using boost::scoped_ptr; 64 using boost::shared_ptr; 65 66 //! Helper object required before GameStates are being constructed 67 struct GameStateInfo 68 { 69 std::string stateName; 70 std::string className; 71 bool bIgnoreTickTime; 72 bool bGraphicsMode; 73 }; 62 74 63 75 /** 64 76 @brief 65 77 Main class responsible for running the game. 78 @remark 79 You should only create this singleton once because it owns the Core class! (see remark there) 66 80 */ 67 class _CoreExport Game 81 class _CoreExport Game : public Singleton<Game> 68 82 { 83 friend class Singleton<Game>; 84 typedef std::vector<shared_ptr<GameState> > GameStateVector; 85 typedef std::map<std::string, shared_ptr<GameState> > GameStateMap; 86 typedef boost::shared_ptr<GameStateTreeNode> GameStateTreeNodePtr; 69 87 public: 70 88 Game(const std::string& cmdLine); … … 72 90 73 91 void setStateHierarchy(const std::string& str); 74 GameState*getState(const std::string& name);92 shared_ptr<GameState> getState(const std::string& name); 75 93 76 94 void run(); … … 86 104 float getAvgFPS() { return this->avgFPS_; } 87 105 88 void addTickTime(uint32_t length);106 void subtractTickTime(int32_t length); 89 107 90 108 template <class T> 91 109 static bool declareGameState(const std::string& className, const std::string& stateName, bool bIgnoreTickTime, bool bConsoleMode); 92 static Game& getInstance() { assert(singletonRef_s); return *singletonRef_s; }93 110 94 111 private: … … 97 114 public: 98 115 virtual ~GameStateFactory() { } 99 static GameState* fabricate(const std::string& className, const GameStateConstrParams& params);116 static shared_ptr<GameState> fabricate(const GameStateInfo& info); 100 117 template <class T> 101 118 static void createFactory(const std::string& className) 102 { factories_s[className] = new TemplateGameStateFactory<T>(); } 103 static void destroyFactories(); 119 { factories_s[className].reset(new TemplateGameStateFactory<T>()); } 104 120 private: 105 virtual GameState* fabricate(const GameStateConstrParams& params) = 0;106 static std::map<std::string, GameStateFactory*> factories_s;121 virtual shared_ptr<GameState> fabricateInternal(const GameStateInfo& info) = 0; 122 static std::map<std::string, shared_ptr<GameStateFactory> > factories_s; 107 123 }; 108 124 template <class T> … … 110 126 { 111 127 public: 112 GameState* fabricate(const GameStateConstrParams& params) 113 { return new T(params); } 114 }; 115 116 struct GameStateInfo 117 { 118 std::string stateName; 119 std::string className; 120 bool bIgnoreTickTime; 121 bool bGraphicsMode; 128 shared_ptr<GameState> fabricateInternal(const GameStateInfo& info) 129 { return shared_ptr<GameState>(new T(info)); } 122 130 }; 123 131 … … 130 138 Game(Game&); // don't mess with singletons 131 139 132 void loadState(GameState* state); 133 void unloadState(GameState* state); 134 135 std::map<std::string, GameState*> gameStates_; 136 std::vector<GameState*> activeStates_; 137 boost::shared_ptr<GameStateTreeNode> rootStateNode_; 138 boost::shared_ptr<GameStateTreeNode> activeStateNode_; 139 std::vector<boost::shared_ptr<GameStateTreeNode> > requestedStateNodes_; 140 141 Core* core_; 142 Clock* gameClock_; 143 GameConfiguration* configuration_; 144 145 bool bChangingState_; 146 bool bAbort_; 140 void loadGraphics(); 141 void unloadGraphics(); 142 143 bool checkState(const std::string& name) const; 144 void loadState(const std::string& name); 145 void unloadState(const std::string& name); 146 147 // Main loop structuring 148 void updateGameStateStack(); 149 void updateGameStates(); 150 void updateStatistics(); 151 void updateFPSLimiter(); 152 153 // ScopeGuard helper function 154 void resetChangingState() { this->bChangingState_ = false; } 155 156 scoped_ptr<Clock> gameClock_; 157 scoped_ptr<Core> core_; 158 scoped_ptr<GameConfiguration> configuration_; 159 160 GameStateMap constructedStates_; 161 GameStateVector loadedStates_; 162 GameStateTreeNodePtr rootStateNode_; 163 GameStateTreeNodePtr loadedTopStateNode_; 164 std::vector<GameStateTreeNodePtr> requestedStateNodes_; 165 166 bool bChangingState_; 167 bool bAbort_; 147 168 148 169 // variables for time statistics 149 uint64_t statisticsStartTime_; 150 std::list<StatisticsTickInfo> statisticsTickTimes_; 151 uint32_t periodTime_; 152 uint32_t periodTickTime_; 153 float avgFPS_; 154 float avgTickTime_; 170 uint64_t statisticsStartTime_; 171 std::list<StatisticsTickInfo> statisticsTickTimes_; 172 uint32_t periodTime_; 173 uint32_t periodTickTime_; 174 float avgFPS_; 175 float avgTickTime_; 176 int excessSleepTime_; 177 unsigned int minimumSleepTime_; 155 178 156 179 static std::map<std::string, GameStateInfo> gameStateDeclarations_s; 157 static Game* singleton Ref_s; //!< Pointer to the Singleton180 static Game* singletonPtr_s; //!< Pointer to the Singleton 158 181 }; 159 182 … … 161 184 /*static*/ bool Game::declareGameState(const std::string& className, const std::string& stateName, bool bIgnoreTickTime, bool bGraphicsMode) 162 185 { 163 std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.find( getLowercase(stateName));186 std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.find(stateName); 164 187 if (it == gameStateDeclarations_s.end()) 165 188 { 166 GameStateInfo& info = gameStateDeclarations_s[ getLowercase(stateName)];189 GameStateInfo& info = gameStateDeclarations_s[stateName]; 167 190 info.stateName = stateName; 168 191 info.className = className; -
code/trunk/src/core/GameMode.h
r2896 r3370 41 41 class _CoreExport GameMode 42 42 { 43 friend class Game; 44 43 45 public: 44 46 static bool showsGraphics() { return bShowsGraphics_s; } … … 47 49 static bool isStandalone() { return bIsStandalone_s; } 48 50 static bool isMaster() { return bIsMaster_s; } 49 static void setShowsGraphics(bool val) { bShowsGraphics_s = val; updateIsMaster(); } 51 50 52 static void setHasServer (bool val) { bHasServer_s = val; updateIsMaster(); } 51 53 static void setIsClient (bool val) { bIsClient_s = val; updateIsMaster(); } 52 54 static void setIsStandalone (bool val) { bIsStandalone_s = val; updateIsMaster(); } 53 static void updateIsMaster () { bIsMaster_s = (bHasServer_s || bIsStandalone_s); }54 55 55 56 private: … … 57 58 GameMode(const GameMode& inst); 58 59 ~GameMode(); 60 61 static void updateIsMaster() 62 { 63 bIsMaster_s = (bHasServer_s || bIsStandalone_s); 64 } 59 65 60 66 static bool bShowsGraphics_s; //!< global variable that tells whether to show graphics -
code/trunk/src/core/GameState.cc
r3280 r3370 38 38 #include "util/Exception.h" 39 39 #include "util/OrxAssert.h" 40 #include "Game.h" 40 41 41 42 namespace orxonox … … 45 46 Constructor only initialises variables and sets the name permanently. 46 47 */ 47 GameState::GameState(const GameStateConstrParams& params) 48 : name_(params.name) 49 , bIgnoreTickTime_(params.bIgnoreTickTime) 50 , parent_(0) 48 GameState::GameState(const GameStateInfo& info) 49 : info_(info) 51 50 { 52 51 this->activity_.activating = false; … … 67 66 } 68 67 69 /** 70 @brief 71 Adds a child to the current tree. The Child can contain children of its own. 72 But you cannot a state tree that already has an active state. 73 @param state 74 The state to be added. 75 */ 76 void GameState::addChild(GameState* state) 68 const std::string& GameState::getName() const 77 69 { 78 assert(state != NULL); 79 80 std::map<std::string, GameState*>::const_iterator it = this->children_.find(state->getName()); 81 if (it == this->children_.end()) 82 { 83 this->children_[state->getName()] = state; 84 // mark us as parent 85 state->setParent(this); 86 } 87 else 88 { 89 ThrowException(GameState, "Cannot add two children with the same name"); 90 } 91 } 92 93 /** 94 @brief 95 Removes a child by instance. This splits the tree in two parts, 96 each of them functional on its own. 97 @param state 98 GameState by instance pointer 99 */ 100 void GameState::removeChild(GameState* state) 101 { 102 assert(state != NULL); 103 104 std::map<std::string, GameState*>::iterator it = this->children_.find(state->getName()); 105 if (it != this->children_.end()) 106 this->children_.erase(it); 107 else 108 { 109 ThrowException(GameState, "Game state '" + name_ + "' doesn't have a child named '" 110 + state->getName() + "'."); 111 } 70 return info_.stateName; 112 71 } 113 72 -
code/trunk/src/core/GameState.h
r3280 r3370 45 45 /** 46 46 @brief 47 Helper class to group construction parameters for better genericity.48 */49 struct GameStateConstrParams50 {51 std::string name;52 bool bIgnoreTickTime;53 };54 55 /**56 @brief57 47 An implementation of a tree to manage game states. 58 48 This leads to a certain hierarchy that is created at runtime. … … 87 77 88 78 public: 89 GameState(const GameState ConstrParams& params);79 GameState(const GameStateInfo& info); 90 80 virtual ~GameState(); 91 81 92 const std::string& getName() const { return name_; } 93 State getActivity() const { return this->activity_; } 94 GameState* getParent() const { return this->parent_; } 95 96 bool ignoreTickTime() const { return this->bIgnoreTickTime_; } 97 98 void addChild(GameState* state); 99 void removeChild(GameState* state); 82 const std::string& getName() const; 83 State getActivity() const { return activity_; } 84 const GameStateInfo& getInfo() const { return info_; } 100 85 101 86 protected: … … 105 90 106 91 private: 107 void setParent(GameState* state) { this->parent_ = state; }108 92 void setActivity(State activity); 109 93 void activateInternal(); … … 111 95 void updateInternal(const Clock& time); 112 96 113 const std::string name_; 114 State activity_; 115 const bool bIgnoreTickTime_; 116 GameState* parent_; 117 std::map<std::string, GameState*> children_; 97 const GameStateInfo& info_; 98 State activity_; 118 99 }; 119 100 } -
code/trunk/src/core/IRC.cc
r3318 r3370 57 57 try 58 58 { 59 this->interpreter_->def(" orxonox::irc::say", IRC::tcl_say, Tcl::variadic());60 this->interpreter_->def(" orxonox::irc::privmsg", IRC::tcl_privmsg, Tcl::variadic());61 this->interpreter_->def(" orxonox::irc::action", IRC::tcl_action, Tcl::variadic());62 this->interpreter_->def(" orxonox::irc::info", IRC::tcl_info, Tcl::variadic());59 this->interpreter_->def("::orxonox::irc::say", IRC::tcl_say, Tcl::variadic()); 60 this->interpreter_->def("::orxonox::irc::privmsg", IRC::tcl_privmsg, Tcl::variadic()); 61 this->interpreter_->def("::orxonox::irc::action", IRC::tcl_action, Tcl::variadic()); 62 this->interpreter_->def("::orxonox::irc::info", IRC::tcl_info, Tcl::variadic()); 63 63 } 64 64 catch (Tcl::tcl_error const &e) -
code/trunk/src/core/Identifier.h
r3333 r3370 500 500 #ifdef ORXONOX_COMPILER_MSVC 501 501 typedef Loki::TypeTraits<typename Loki::TypeTraits<T>::PointeeType>::NonConstType ClassType; 502 return source->template getDerivedPointer<ClassType>(ClassIdentifier<ClassType>::getIdentifier()->getClassID()); 502 if (source != NULL) 503 return source->template getDerivedPointer<ClassType>(ClassIdentifier<ClassType>::getIdentifier()->getClassID()); 504 else 505 return NULL; 503 506 #else 504 507 return dynamic_cast<T>(source); -
code/trunk/src/core/Language.cc
r3280 r3370 89 89 // ############################### 90 90 91 Language* Language::singleton Ref_s = 0;91 Language* Language::singletonPtr_s = 0; 92 92 93 93 /** … … 96 96 Language::Language() 97 97 { 98 assert(singletonRef_s == 0);99 singletonRef_s = this;100 101 98 this->defaultLanguage_ = "default"; 102 99 this->defaultLocalisation_ = "ERROR: LANGUAGE ENTRY DOESN'T EXIST!"; … … 113 110 for (std::map<std::string, LanguageEntry*>::iterator it = this->languageEntries_.begin(); it != this->languageEntries_.end(); ++it) 114 111 delete (it->second); 115 116 assert(singletonRef_s);117 singletonRef_s = 0;118 112 } 119 113 -
code/trunk/src/core/Language.h
r3280 r3370 37 37 Usage: 38 38 - Set the entry with the default string: 39 Language::get Language()->addEntry("label of the entry", "the string to translate");39 Language::getInstance()->addEntry("label of the entry", "the string to translate"); 40 40 41 41 - Get the localisation of the entry in the configured language: 42 std::cout << Language::get Language()->getLocalisation("name of the entry") << std::endl;42 std::cout << Language::getInstance()->getLocalisation("name of the entry") << std::endl; 43 43 */ 44 44 … … 51 51 #include <string> 52 52 #include <cassert> 53 #include "util/Singleton.h" 53 54 54 55 #define AddLanguageEntry(label, fallbackstring) \ 55 orxonox::Language::get Language().addEntry(label, fallbackstring)56 orxonox::Language::getInstance().addEntry(label, fallbackstring) 56 57 57 58 #define GetLocalisation(label) \ 58 orxonox::Language::get Language().getLocalisation(label)59 orxonox::Language::getInstance().getLocalisation(label) 59 60 60 61 … … 112 113 // ############################### 113 114 //! The Language class manges the language files and entries and stores the LanguageEntry objects in a map. 114 class _CoreExport Language 115 class _CoreExport Language : public Singleton<Language> 115 116 { 117 friend class Singleton<Language>; 116 118 friend class CoreConfiguration; 117 119 … … 120 122 ~Language(); 121 123 122 static Language& getLanguage() { assert(singletonRef_s); return *singletonRef_s; }123 124 void addEntry(const LanguageEntryLabel& label, const std::string& entry); 124 125 const std::string& getLocalisation(const LanguageEntryLabel& label) const; … … 137 138 std::map<std::string, LanguageEntry*> languageEntries_; //!< A map to store all LanguageEntry objects and their labels 138 139 139 static Language* singleton Ref_s;140 static Language* singletonPtr_s; 140 141 }; 141 142 } -
code/trunk/src/core/Loader.cc
r3196 r3370 30 30 31 31 #include <tinyxml/ticpp.h> 32 #include <boost/filesystem.hpp>33 32 34 33 #include "util/Debug.h" 35 34 #include "util/Exception.h" 36 35 #include "BaseObject.h" 37 #include "Core.h"38 36 #include "Iterator.h" 39 37 #include "ObjectList.h" … … 210 208 return Loader::load(file, mask); 211 209 } 212 213 std::vector<std::string> Loader::getLevelList()214 {215 std::vector<std::string> levelList;216 217 boost::filesystem::directory_iterator file(Core::getMediaPathString() + "levels");218 boost::filesystem::directory_iterator end;219 220 while (file != end)221 {222 if (!boost::filesystem::is_directory(*file) && file->string()[file->string().length()-1] != '~')223 {224 std::string filename = file->path().leaf();225 if (filename.length() > 4)226 levelList.push_back(filename.substr(0,filename.length()-4));227 }228 ++file;229 }230 return levelList;231 }232 210 } -
code/trunk/src/core/Loader.h
r3196 r3370 56 56 57 57 static ClassTreeMask currentMask_s; 58 static std::vector<std::string> getLevelList();59 58 60 59 private: -
code/trunk/src/core/LuaBind.cc
r3301 r3370 39 39 #include "util/Debug.h" 40 40 #include "util/StringUtils.h" 41 #include "ToluaBindCore.h"42 41 #include "Core.h" 43 42 44 43 namespace orxonox 45 44 { 46 LuaBind* LuaBind::singleton Ref_s = NULL;45 LuaBind* LuaBind::singletonPtr_s = NULL; 47 46 48 47 LuaBind::LuaBind() 49 48 { 50 assert(LuaBind::singletonRef_s == 0);51 LuaBind::singletonRef_s = this;52 53 49 this->includePath_ = Core::getMediaPathString(); 54 50 … … 65 61 luaopen_debug(luaState_); 66 62 #endif 67 tolua_Core_open(luaState_); 63 64 // Open all available tolua interfaces 65 this->openToluaInterfaces(luaState_); 66 68 67 output_ = ""; 69 68 isRunning_ = false; 70 69 } 70 71 LuaBind::~LuaBind() 72 { 73 this->closeToluaInterfaces(luaState_); 74 }; 71 75 72 76 void LuaBind::luaPrint(const std::string& str) … … 315 319 } 316 320 321 void LuaBind::addToluaInterface(int (*function)(lua_State*), const std::string& name) 322 { 323 toluaInterfaces_.push_back(std::make_pair(name, function)); 324 // Apply changes to our own lua state as well 325 (*function)(luaState_); 326 } 327 328 void LuaBind::openToluaInterfaces(lua_State* state) 329 { 330 for (unsigned int i = 0; i < toluaInterfaces_.size(); ++i) 331 (*toluaInterfaces_[i].second)(state); 332 } 333 334 void LuaBind::closeToluaInterfaces(lua_State* state) 335 { 336 for (unsigned int i = 0; i < toluaInterfaces_.size(); ++i) 337 { 338 lua_pushnil(state); 339 lua_setglobal(state, toluaInterfaces_[i].first.c_str()); 340 } 341 } 342 317 343 } -
code/trunk/src/core/LuaBind.h
r3196 r3370 40 40 #include <cassert> 41 41 #include <string> 42 #include <vector> 42 43 extern "C" { 43 44 #include <lua.h> 44 45 } 45 46 47 #include "util/Singleton.h" 48 46 49 // tolua_begin 47 50 namespace orxonox 48 51 { 49 class _CoreExport LuaBind 52 class _CoreExport LuaBind : public Singleton<LuaBind> 50 53 { 54 // tolua_end 55 friend class Singleton<LuaBind>; 51 56 52 // tolua_end53 57 struct LoadS { 54 58 const char *s; … … 58 62 public: 59 63 LuaBind(); 60 inline ~LuaBind() { assert(singletonRef_s); LuaBind::singletonRef_s = NULL; };64 ~LuaBind(); 61 65 62 inline static LuaBind& getInstance() { assert(singletonRef_s); return *LuaBind::singletonRef_s; } // tolua_export66 static LuaBind& getInstance() { return Singleton<LuaBind>::getInstance(); } // tolua_export 63 67 64 68 void loadFile(const std::string& filename, bool luaTags); … … 83 87 { this->includePath_ = includepath; } 84 88 89 void addToluaInterface(int (*function)(lua_State*), const std::string& name); 90 void openToluaInterfaces(lua_State* state); 91 void closeToluaInterfaces(lua_State* state); 92 85 93 private: 86 static LuaBind* singleton Ref_s;94 static LuaBind* singletonPtr_s; 87 95 88 96 std::string luaSource_; … … 91 99 bool isRunning_; 92 100 std::string includePath_; 101 std::vector<std::pair<std::string, int (*)(lua_State *L)> > toluaInterfaces_; 93 102 94 103 }; // tolua_export -
code/trunk/src/core/Shell.cc
r3301 r3370 51 51 SetConsoleCommandShortcut(OutputHandler, debug); 52 52 53 Shell* Shell::singleton Ref_s = 0;53 Shell* Shell::singletonPtr_s = 0; 54 54 55 55 Shell::Shell() 56 56 { 57 assert(singletonRef_s == 0);58 singletonRef_s = this;59 60 57 int level = Core::getSoftDebugLevel(OutputHandler::LD_Shell); 61 58 Core::setSoftDebugLevel(OutputHandler::LD_Shell, -1); … … 92 89 if (this->inputBuffer_) 93 90 delete this->inputBuffer_; 94 singletonRef_s = 0;95 91 } 96 92 -
code/trunk/src/core/Shell.h
r3280 r3370 60 60 }; 61 61 62 class _CoreExport Shell : virtual public OrxonoxClass, public OutputBufferListener62 class _CoreExport Shell : public Singleton<Shell>, virtual public OrxonoxClass, public OutputBufferListener 63 63 { 64 friend class Singleton<Shell>; 64 65 public: 65 66 Shell(); 66 67 virtual ~Shell(); 67 68 static Shell& getInstance() { assert(singletonRef_s); return *singletonRef_s; }69 68 70 69 static void clearShell(); … … 148 147 ConfigFileType commandHistoryConfigFileType_; 149 148 150 static Shell* singleton Ref_s;149 static Shell* singletonPtr_s; 151 150 }; 152 151 } -
code/trunk/src/core/TclBind.cc
r3318 r3370 33 33 #include <cpptcl/cpptcl.h> 34 34 35 #include "SpecialConfig.h" 35 36 #include "util/Debug.h" 36 37 #include "util/StringUtils.h" 37 38 #include "CommandExecutor.h" 38 39 #include "ConsoleCommand.h" 40 #include "Core.h" 39 41 #include "TclThreadManager.h" 40 42 … … 44 46 SetConsoleCommandShortcut(TclBind, bgerror); 45 47 46 TclBind* TclBind::singleton Ref_s = 0;48 TclBind* TclBind::singletonPtr_s = 0; 47 49 48 50 TclBind::TclBind(const std::string& datapath) 49 51 { 50 assert(singletonRef_s == 0);51 singletonRef_s = this;52 52 this->interpreter_ = 0; 53 this->bSetTcl LibPath_ = false;53 this->bSetTclDataPath_ = false; 54 54 this->setDataPath(datapath); 55 55 } … … 59 59 if (this->interpreter_) 60 60 delete this->interpreter_; 61 singletonRef_s = 0;62 61 } 63 62 … … 65 64 { 66 65 // String has POSIX slashes 67 this->tclLibPath_ = datapath + "tcl" + TCL_VERSION + '/'; 68 this->bSetTclLibPath_ = true; 69 70 this->createTclInterpreter(); 71 } 72 73 void TclBind::createTclInterpreter() 74 { 75 if (this->bSetTclLibPath_ && !this->interpreter_) 76 { 77 this->interpreter_ = new Tcl::interpreter(this->tclLibPath_); 78 this->interpreter_->def("orxonox::query", TclBind::tcl_query, Tcl::variadic()); 79 this->interpreter_->def("orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic()); 66 this->tclDataPath_ = datapath + "tcl" + '/'; 67 this->bSetTclDataPath_ = true; 68 69 this->initializeTclInterpreter(); 70 } 71 72 void TclBind::initializeTclInterpreter() 73 { 74 if (this->bSetTclDataPath_ && !this->interpreter_) 75 { 76 this->interpreter_ = this->createTclInterpreter(); 77 78 this->interpreter_->def("::orxonox::query", TclBind::tcl_query, Tcl::variadic()); 79 this->interpreter_->def("::orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic()); 80 80 this->interpreter_->def("execute", TclBind::tcl_execute, Tcl::variadic()); 81 this->interpreter_->def(" orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());81 this->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 82 82 83 83 try 84 84 { 85 this->interpreter_->eval("proc query args { orxonox::query [join $args] }"); 86 this->interpreter_->eval("proc crossquery {id args} { orxonox::crossquery 0 $id [join $args] }"); 87 this->interpreter_->eval("proc crossexecute {id args} { orxonox::crossquery 0 $id [join $args] }"); 85 this->interpreter_->eval("proc query {args} { ::orxonox::query $args }"); 86 this->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery 0 $id $args }"); 87 this->interpreter_->eval("proc crossexecute {id args} { ::orxonox::crossquery 0 $id $args }"); 88 this->interpreter_->eval("proc running {} { return 1 }"); 88 89 this->interpreter_->eval("set id 0"); 89 this->interpreter_->eval("rename exit tcl::exit; proc exit {} { execute exit }"); 90 this->interpreter_->eval("redef_puts"); 90 this->interpreter_->eval("rename exit ::tcl::exit; proc exit {} { execute exit }"); 91 91 } 92 92 catch (Tcl::tcl_error const &e) … … 94 94 catch (std::exception const &e) 95 95 { COUT(1) << "Error while creating Tcl-interpreter: " << e.what() << std::endl; } 96 } 97 } 98 99 void TclBind::createNewTclInterpreter() 100 { 101 if (this->interpreter_) 102 { 103 delete this->interpreter_; 104 this->interpreter_ = 0; 105 } 106 107 this->createTclInterpreter(); 96 catch (...) 97 { COUT(1) << "Error while creating Tcl-interpreter." << std::endl; } 98 } 99 } 100 101 Tcl::interpreter* TclBind::createTclInterpreter() 102 { 103 Tcl::interpreter* interpreter = new Tcl::interpreter(); 104 std::string libpath = TclBind::getTclLibraryPath(); 105 106 try 107 { 108 if (libpath != "") 109 interpreter->eval("set tcl_library \"" + libpath + "\""); 110 111 Tcl_Init(interpreter->get()); 112 113 interpreter->eval("source \"" + TclBind::getInstance().tclDataPath_ + "/init.tcl\""); 114 } 115 catch (Tcl::tcl_error const &e) 116 { COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl; } 117 catch (std::exception const &e) 118 { COUT(1) << "Error while creating Tcl-interpreter: " << e.what() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl; } 119 catch (...) 120 { COUT(1) << "Error while creating Tcl-interpreter." << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl; } 121 122 return interpreter; 123 } 124 125 std::string TclBind::getTclLibraryPath() 126 { 127 #ifdef DEPENDENCY_PACKAGE_ENABLE 128 if (Core::isDevelopmentRun()) 129 return (std::string(ORXONOX_DEP_LIB_PATH) + "/tcl"); 130 else 131 return (Core::getRootPathString() + "lib/tcl"); 132 #else 133 return ""; 134 #endif 108 135 } 109 136 … … 142 169 try 143 170 { 144 std::string output = TclBind::getInstance().interpreter_->eval( tclcode);171 std::string output = TclBind::getInstance().interpreter_->eval("uplevel #0 " + tclcode); 145 172 if (output != "") 146 173 { -
code/trunk/src/core/TclBind.h
r3196 r3370 34 34 #include <cassert> 35 35 #include <string> 36 #include "util/Singleton.h" 36 37 37 38 namespace orxonox 38 39 { 39 class _CoreExport TclBind 40 class _CoreExport TclBind : public Singleton<TclBind> 40 41 { 42 friend class Singleton<TclBind>; 41 43 public: 42 44 TclBind(const std::string& datapath); 43 45 ~TclBind(); 44 45 static TclBind& getInstance() { assert(singletonRef_s); return *singletonRef_s; }46 46 47 47 static std::string tcl(const std::string& tclcode); … … 49 49 50 50 void setDataPath(const std::string& datapath); 51 std::string getTclLibPath() const { return this->tclLibPath_; } 52 void createTclInterpreter(); 53 void createNewTclInterpreter(); 51 const std::string& getTclDataPath() const { return this->tclDataPath_; } 52 static std::string getTclLibraryPath(); 53 54 void initializeTclInterpreter(); 55 static Tcl::interpreter* createTclInterpreter(); 54 56 Tcl::interpreter* getTclInterpreter() const { return this->interpreter_; } 55 57 … … 63 65 64 66 Tcl::interpreter* interpreter_; 65 std::string tcl LibPath_;66 bool bSetTcl LibPath_;67 std::string tclDataPath_; 68 bool bSetTclDataPath_; 67 69 68 static TclBind* singleton Ref_s;70 static TclBind* singletonPtr_s; 69 71 }; 70 72 } -
code/trunk/src/core/TclThreadManager.cc
r3326 r3370 54 54 SetConsoleCommand(TclThreadManager, execute, false).argumentCompleter(0, autocompletion::tclthreads()); 55 55 SetConsoleCommand(TclThreadManager, query, false).argumentCompleter(0, autocompletion::tclthreads()); 56 SetConsoleCommand(TclThreadManager, source, false).argumentCompleter(0, autocompletion::tclthreads()); 56 57 57 58 /** … … 90 91 RegisterRootObject(TclThreadManager); 91 92 92 assert(TclThreadManager::singletonPtr_s == 0);93 TclThreadManager::singletonPtr_s = this;94 95 93 this->numInterpreterBundles_ = 0; 96 94 … … 115 113 TclThreadManager::~TclThreadManager() 116 114 { 117 TclThreadManager::singletonPtr_s = 0;118 119 115 delete this->interpreterBundlesMutex_; 120 116 // delete this->mainInterpreterMutex_; // <-- temporary disabled to avoid crash if a thread is still actively queriyng … … 240 236 TclInterpreterBundle* newbundle = new TclInterpreterBundle(); 241 237 newbundle->id_ = id; 242 newbundle->interpreter_ = new Tcl::interpreter(TclBind::getInstance().getTclLibPath()); 243 244 // Initialize the new interpreter 245 try 246 { 247 std::string id_string = getConvertedValue<unsigned int, std::string>(id); 248 249 // Define the functions which are implemented in C++ 250 newbundle->interpreter_->def("orxonox::execute", TclThreadManager::tcl_execute, Tcl::variadic()); 251 newbundle->interpreter_->def("orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 252 newbundle->interpreter_->def("orxonox::query", TclThreadManager::tcl_query, Tcl::variadic()); 253 newbundle->interpreter_->def("orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic()); 254 newbundle->interpreter_->def("orxonox::running", TclThreadManager::tcl_running); 255 256 // Create threadspecific shortcuts for the functions above 257 newbundle->interpreter_->def("execute", TclThreadManager::tcl_execute, Tcl::variadic()); 258 newbundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 259 newbundle->interpreter_->eval("proc query args { orxonox::query " + id_string + " $args }"); 260 newbundle->interpreter_->eval("proc crossquery {id args} { orxonox::crossquery " + id_string + " $id $args }"); 261 262 // Define a variable containing the thread id 263 newbundle->interpreter_->eval("set id " + id_string); 264 265 // Use our own exit function to avoid shutting down the whole program instead of just the interpreter 266 newbundle->interpreter_->eval("rename exit tcl::exit"); 267 newbundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }"); 268 269 // Redefine some native functions 270 newbundle->interpreter_->eval("redef_puts"); 271 272 // newbundle->interpreter_->eval("rename while tcl::while"); 273 // newbundle->interpreter_->eval("proc while {test command} { tcl::while {[uplevel 1 expr $test]} {uplevel 1 $command} }"); // (\"$test\" && [orxonox::running " + id + "]]) 274 // newbundle->interpreter_->eval("rename for tcl::for"); 275 // newbundle->interpreter_->eval("proc for {start test next command} { uplevel tcl::for \"$start\" \"$test\" \"$next\" \"$command\" }"); 276 } 277 catch (const Tcl::tcl_error& e) 278 { newbundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl; } 279 catch (const std::exception& e) 280 { newbundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id << "): " << e.what() << std::endl; } 281 catch (...) 282 { newbundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id << ")" << std::endl; } 238 newbundle->interpreter_ = TclBind::createTclInterpreter(); 239 240 TclThreadManager::initialize(newbundle); 283 241 284 242 { … … 291 249 } 292 250 251 void TclThreadManager::initialize(TclInterpreterBundle* bundle) 252 { 253 std::string id_string = getConvertedValue<unsigned int, std::string>(bundle->id_); 254 255 // Initialize the new interpreter 256 try 257 { 258 // Define the functions which are implemented in C++ 259 bundle->interpreter_->def("::orxonox::execute", TclThreadManager::tcl_execute, Tcl::variadic()); 260 bundle->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 261 bundle->interpreter_->def("::orxonox::query", TclThreadManager::tcl_query, Tcl::variadic()); 262 bundle->interpreter_->def("::orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic()); 263 bundle->interpreter_->def("::orxonox::running", TclThreadManager::tcl_running); 264 265 // Create threadspecific shortcuts for the functions above 266 bundle->interpreter_->def("execute", TclThreadManager::tcl_execute, Tcl::variadic()); 267 bundle->interpreter_->def("crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic()); 268 bundle->interpreter_->eval("proc query {args} { ::orxonox::query " + id_string + " $args }"); 269 bundle->interpreter_->eval("proc crossquery {id args} { ::orxonox::crossquery " + id_string + " $id $args }"); 270 bundle->interpreter_->eval("proc running {} { return [::orxonox::running " + id_string + "] }"); 271 272 // Define a variable containing the thread id 273 bundle->interpreter_->eval("set id " + id_string); 274 275 // Use our own exit function to avoid shutting down the whole program instead of just the interpreter 276 bundle->interpreter_->eval("rename exit ::tcl::exit"); 277 bundle->interpreter_->eval("proc exit {} { execute TclThreadManager destroy " + id_string + " }"); 278 279 // Redefine some native functions 280 bundle->interpreter_->eval("rename while ::tcl::while"); 281 bundle->interpreter_->eval("rename ::orxonox::while while"); 282 bundle->interpreter_->eval("rename for ::tcl::for"); 283 bundle->interpreter_->eval("rename ::orxonox::for for"); 284 } 285 catch (const Tcl::tcl_error& e) 286 { bundle->interpreter_ = 0; COUT(1) << "Tcl error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl; } 287 catch (const std::exception& e) 288 { bundle->interpreter_ = 0; COUT(1) << "Error while creating Tcl-interpreter (" << id_string << "): " << e.what() << std::endl; } 289 catch (...) 290 { bundle->interpreter_ = 0; COUT(1) << "An error occurred while creating a new Tcl-interpreter (" << id_string << ")" << std::endl; } 291 } 292 293 293 /** 294 294 @brief Stops and destroys a given Tcl-interpreter … … 298 298 // TODO 299 299 // Not yet implemented 300 TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id); 301 if (bundle) 302 { 303 bundle->bRunning_ = false; 304 } 300 305 } 301 306 … … 399 404 { 400 405 // This query would lead to a deadlock - return with an error 401 this->error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \406 TclThreadManager::error("Error: Circular query (" + this->dumpList(source_bundle->queriers_.getList()) + " " + getConvertedValue<unsigned int, std::string>(source_bundle->id_) \ 402 407 + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \ 403 408 + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \ … … 435 440 { 436 441 // It's a query to the CommandExecutor 437 this->debug("TclThread_query -> CE: " + command);442 TclThreadManager::debug("TclThread_query -> CE: " + command); 438 443 if (!CommandExecutor::execute(command, false)) 439 this->error("Error: Can't execute command \"" + command + "\"!");444 TclThreadManager::error("Error: Can't execute command \"" + command + "\"!"); 440 445 441 446 if (CommandExecutor::getLastEvaluation().hasReturnvalue()) … … 445 450 { 446 451 // It's a query to a Tcl interpreter 447 this->debug("TclThread_query: " + command);448 449 output = this->eval(target_bundle, command);452 TclThreadManager::debug("TclThread_query: " + command); 453 454 output = TclThreadManager::eval(target_bundle, command, "query"); 450 455 } 451 456 … … 464 469 // This happens if the main thread tries to query a busy interpreter 465 470 // To avoid a lock of the main thread, we simply don't proceed with the query in this case 466 this->error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now.");471 TclThreadManager::error("Error: Couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) + ", interpreter is busy right now."); 467 472 } 468 473 } … … 471 476 472 477 return output; 478 } 479 480 /** 481 @brief Creates a non-interactive Tcl-interpreter which executes a file. 482 */ 483 void TclThreadManager::source(const std::string& file) 484 { 485 boost::thread(boost::bind(&sourceThread, file)); 473 486 } 474 487 … … 502 515 else 503 516 { 504 this->error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing.");517 TclThreadManager::error("Error: No Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(id) + " existing."); 505 518 return 0; 506 519 } … … 544 557 void TclThreadManager::error(const std::string& error) 545 558 { 546 this->messageQueue_->push_back("error " + error);559 TclThreadManager::getInstance().messageQueue_->push_back("error " + error); 547 560 } 548 561 … … 552 565 void TclThreadManager::debug(const std::string& error) 553 566 { 554 this->messageQueue_->push_back("debug " + error);567 TclThreadManager::getInstance().messageQueue_->push_back("debug " + error); 555 568 } 556 569 … … 561 574 Errors are reported through the @ref error function. 562 575 */ 563 std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command )576 std::string TclThreadManager::eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action) 564 577 { 565 578 Tcl_Interp* interpreter = bundle->interpreter_->get(); … … 570 583 if (cc != TCL_OK) 571 584 { 572 this->error("Tcl error (execute, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result));585 TclThreadManager::error("Tcl error (" + action + ", ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result)); 573 586 return ""; 574 587 } … … 590 603 void tclThread(TclInterpreterBundle* bundle, std::string command) 591 604 { 592 TclThreadManager:: getInstance().debug("TclThread_execute: " + command);593 594 TclThreadManager:: getInstance().eval(bundle, command);605 TclThreadManager::debug("TclThread_execute: " + command); 606 607 TclThreadManager::eval(bundle, command, "execute"); 595 608 596 609 bundle->lock_->unlock(); 597 610 } 611 612 /** 613 @brief The main function of a non-interactive source thread. Executes the file. 614 @param file The name of the file that should be executed by the non-interactive interpreter. 615 */ 616 void sourceThread(std::string file) 617 { 618 TclThreadManager::debug("TclThread_source: " + file); 619 620 // Prepare the command-line arguments 621 const int argc = 2; 622 char* argv[argc]; 623 argv[0] = "tclthread"; 624 argv[1] = const_cast<char*>(file.c_str()); 625 626 // Start the Tcl-command Tcl_Main with the Tcl_OrxonoxAppInit hook 627 Tcl_Main(argc, argv, Tcl_OrxonoxAppInit); 628 629 // Tcl::object object(file); 630 // int cc = Tcl_FSEvalFile(bundle->interpreter_->get(), object.get_object()); 631 // Tcl::details::result result(bundle->interpreter_->get()); 632 // if (cc != TCL_OK) 633 // TclThreadManager::error("Tcl error (source, ID " + getConvertedValue<unsigned int, std::string>(bundle->id_) + "): " + static_cast<std::string>(result)); 634 // 635 // // Unlock the mutex 636 // bundle->lock_->unlock(); 637 } 638 639 /** 640 @brief A tcl-init hook to inject the non-interactive Tcl-interpreter into the TclThreadManager. 641 */ 642 int Tcl_OrxonoxAppInit(Tcl_Interp* interp) 643 { 644 // Create a new interpreter bundle 645 unsigned int id = TclThreadManager::create(); 646 TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id); 647 648 // Replace the default interpreter in the bundle with the non-interactive one (passed as an argument to this function) 649 if (bundle->interpreter_) 650 delete bundle->interpreter_; 651 bundle->interpreter_ = new Tcl::interpreter(interp, true); 652 653 // Initialize the non-interactive interpreter (like in @ref TclBind::createTclInterpreter but exception safe) 654 std::string libpath = TclBind::getTclLibraryPath(); 655 if (libpath != "") 656 TclThreadManager::eval(bundle, "set tcl_library \"" + libpath + "\"", "source"); 657 int cc = Tcl_Init(interp); 658 TclThreadManager::eval(bundle, "source \"" + TclBind::getInstance().getTclDataPath() + "/init.tcl\"", "source"); 659 660 // Initialize the non-interactive interpreter also with the thread-specific stuff 661 TclThreadManager::initialize(bundle); 662 663 // Lock the mutex (this will be locked until the thread finishes - no chance to interact with the interpreter) 664 bundle->lock_->lock(); 665 666 // Return to Tcl_Main 667 if (!bundle->interpreter_) 668 return TCL_ERROR; 669 else 670 return cc; 671 } 598 672 } -
code/trunk/src/core/TclThreadManager.h
r3321 r3370 33 33 34 34 #include <cassert> 35 #include <list> 35 36 #include <map> 36 37 #include <string> 37 38 39 #include "util/Singleton.h" 38 40 #include "OrxonoxClass.h" 41 42 struct Tcl_Interp; 39 43 40 44 namespace orxonox 41 45 { 42 class _CoreExport TclThreadManager : public OrxonoxClass46 class _CoreExport TclThreadManager : public Singleton<TclThreadManager>, public OrxonoxClass 43 47 { 48 friend class Singleton<TclThreadManager>; 44 49 friend class TclBind; 45 50 friend _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command); 51 friend _CoreExport void sourceThread(std::string file); 52 friend _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp); 46 53 47 54 public: 48 55 TclThreadManager(Tcl::interpreter* interpreter); 49 56 virtual ~TclThreadManager(); 50 51 static TclThreadManager& getInstance() { assert(TclThreadManager::singletonPtr_s); return *TclThreadManager::singletonPtr_s; }52 57 53 58 static unsigned int create(); … … 56 61 static void execute(unsigned int target_id, const std::string& command); 57 62 static std::string query(unsigned int target_id, const std::string& command); 63 static void source(const std::string& file); 58 64 59 void error(const std::string& error);60 void debug(const std::string& error);65 static void error(const std::string& error); 66 static void debug(const std::string& error); 61 67 62 68 void update(const Clock& time); … … 77 83 std::string dumpList(const std::list<unsigned int>& list); 78 84 79 std::string eval(TclInterpreterBundle* bundle, const std::string& command); 85 static void initialize(TclInterpreterBundle* bundle); 86 static std::string eval(TclInterpreterBundle* bundle, const std::string& command, const std::string& action); 80 87 81 88 static TclThreadManager* singletonPtr_s; ///< Singleton pointer … … 89 96 90 97 _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command); 98 _CoreExport void sourceThread(std::string file); 99 _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp); 91 100 } 92 101 -
code/trunk/src/core/input/InputManager.cc
r3331 r3370 64 64 InputHandler InputHandler::EMPTY; 65 65 66 InputManager* InputManager::singleton Ref_s = 0;66 InputManager* InputManager::singletonPtr_s = 0; 67 67 68 68 //! Defines the |= operator for easier use. … … 93 93 RegisterRootObject(InputManager); 94 94 95 assert(singletonRef_s == 0);96 singletonRef_s = this;97 98 95 CCOUT(4) << "Constructing..." << std::endl; 99 96 … … 138 135 } 139 136 137 CCOUT(4) << "Construction complete." << std::endl; 140 138 internalState_ = Nothing; 141 CCOUT(4) << "Construction complete." << std::endl;142 139 } 143 140 … … 297 294 298 295 CCOUT(4) << "Destruction complete." << std::endl; 299 singletonRef_s = 0;300 296 } 301 297 -
code/trunk/src/core/input/InputManager.h
r3327 r3370 37 37 #include <vector> 38 38 39 #include "util/Singleton.h" 39 40 #include "core/WindowEventListener.h" 40 41 #include "InputState.h" … … 62 63 If the OIS::InputManager or the Keyboard fail, an exception is thrown. 63 64 */ 64 class _CoreExport InputManager : public WindowEventListener65 class _CoreExport InputManager : public Singleton<InputManager>, public WindowEventListener 65 66 { 67 friend class Singleton<InputManager>; 66 68 public: 67 69 //! Represents internal states of the InputManager. … … 168 170 { return this->oisInputManager_; } 169 171 170 //! Returns a reference to the singleton instance171 static InputManager& getInstance() { assert(singletonRef_s); return *singletonRef_s; }172 173 172 private: // functions 174 173 // don't mess with a Singleton … … 211 210 std::set<InputState*> stateDestroyRequests_; //!< Requests to destroy a state 212 211 213 static InputManager* singleton Ref_s; //!< Pointer reference to the singleton212 static InputManager* singletonPtr_s; //!< Pointer reference to the singleton 214 213 }; 215 214 }
Note: See TracChangeset
for help on using the changeset viewer.