Changeset 7421 for sandbox_qt/src/libraries/core
- Timestamp:
- Sep 12, 2010, 12:47:30 AM (14 years ago)
- Location:
- sandbox_qt/src/libraries/core
- Files:
-
- 1 deleted
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
sandbox_qt/src/libraries/core/CMakeLists.txt
r7284 r7421 19 19 20 20 SET_SOURCE_FILES(CORE_SRC_FILES 21 CommandLineParser.cc22 ConfigValueContainer.cc23 21 Core.cc 24 DynLib.cc25 DynLibManager.cc26 Event.cc27 22 Game.cc 28 GameMode.cc29 GameState.cc30 GraphicsManager.cc31 GUIManager.cc32 Language.cc33 LuaState.cc34 ObjectListBase.cc35 OrxonoxClass.cc36 Resource.cc37 WindowEventListener.cc38 39 # hierarchy40 Identifier.cc41 MetaObjectList.cc42 43 # level44 BaseObject.cc45 ClassTreeMask.cc46 Loader.cc47 Namespace.cc48 NamespaceNode.cc49 Template.cc50 XMLPort.cc51 XMLNameListener.cc52 53 COMPILATION_BEGIN FilesystemCompilation.cc54 command/ArgumentCompletionFunctions.cc55 ConfigFileManager.cc56 MemoryArchive.cc57 23 PathConfig.cc 58 COMPILATION_END59 60 # multithreading61 ThreadPool.cc62 COMPILATION_BEGIN ThreadCompilation.cc63 command/TclThreadManager.cc64 Thread.cc65 COMPILATION_END66 24 ) 67 68 ADD_SUBDIRECTORY(command)69 ADD_SUBDIRECTORY(input)70 25 71 26 ORXONOX_ADD_LIBRARY(core 72 27 FIND_HEADER_FILES 73 TOLUA_FILES74 command/CommandExecutor.h75 ConfigFileManager.h76 Game.h77 GameMode.h78 GUIManager.h79 Loader.h80 LuaState.h81 PathConfig.h82 input/InputManager.h83 input/KeyBinder.h84 input/KeyBinderManager.h85 PCH_FILE86 CorePrecompiledHeaders.h87 28 LINK_LIBRARIES 88 ${OGRE_LIBRARY} 89 ${Boost_FILESYSTEM_LIBRARY} 90 ${Boost_SYSTEM_LIBRARY} # Filesystem dependency 91 ${Boost_THREAD_LIBRARY} 92 ${Boost_DATE_TIME_LIBRARY} # Thread dependency 93 ${CEGUI_LIBRARY} 94 ${CEGUILUA_LIBRARY} 95 ${LUA_LIBRARIES} 96 cpptcl_orxonox 97 ogreceguirenderer_orxonox 98 ois_orxonox 99 tinyxml_orxonox 100 tolua_orxonox 29 ${QT_QTCORE_LIBRARY} 101 30 util 102 31 SOURCE_FILES -
sandbox_qt/src/libraries/core/Core.cc
r7401 r7421 31 31 @file 32 32 @brief 33 Implementation of the Core singleton with its global variables (avoids boost include)33 Implementation of the Core singleton 34 34 */ 35 35 … … 37 37 38 38 #include <cassert> 39 #include <ctime> 39 40 #include <fstream> 40 41 #include <vector> … … 49 50 #endif 50 51 51 #include "util/Clock.h"52 52 #include "util/Debug.h" 53 53 #include "util/Exception.h" 54 #include "util/Scope.h"55 #include "util/ScopedSingletonManager.h"56 #include "util/SignalHandler.h"57 54 #include "PathConfig.h" 58 #include "CommandLineParser.h"59 #include "ConfigFileManager.h"60 #include "ConfigValueIncludes.h"61 #include "CoreIncludes.h"62 #include "DynLibManager.h"63 #include "GameMode.h"64 #include "GraphicsManager.h"65 #include "GUIManager.h"66 #include "Identifier.h"67 #include "Language.h"68 #include "LuaState.h"69 #include "command/ConsoleCommand.h"70 #include "command/IOConsole.h"71 #include "command/TclBind.h"72 #include "command/TclThreadManager.h"73 #include "input/InputManager.h"74 55 75 56 namespace orxonox … … 78 59 Core* Core::singletonPtr_s = 0; 79 60 80 SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");81 SetCommandLineSwitch(noIOConsole).information("Use this if you don't want to use the IOConsole (for instance for Lua debugging)");82 83 #ifdef ORXONOX_PLATFORM_WINDOWS84 SetCommandLineArgument(limitToCPU, 1).information("Limits the program to one CPU/core (1, 2, 3, etc.). Default is the first core (faster than off)");85 #endif86 87 61 Core::Core(const std::string& cmdLine) 88 // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)89 : identifierDestroyer_(Identifier::destroyAllIdentifiers)90 // Cleanup guard for external console commands that don't belong to an Identifier91 , consoleCommandDestroyer_(ConsoleCommand::destroyAll)92 , bGraphicsLoaded_(false)93 , bStartIOConsole_(true)94 62 { 95 63 // Set the hard coded fixed paths 96 64 this->pathConfig_.reset(new PathConfig()); 97 65 98 // Create a new dynamic library manager99 this->dynLibManager_.reset(new DynLibManager());100 101 // Load modules102 const std::vector<std::string>& modulePaths = this->pathConfig_->getModulePaths();103 for (std::vector<std::string>::const_iterator it = modulePaths.begin(); it != modulePaths.end(); ++it)104 {105 try106 {107 this->dynLibManager_->load(*it);108 }109 catch (...)110 {111 COUT(1) << "Couldn't load module \"" << *it << "\": " << Exception::handleMessage() << std::endl;112 }113 }114 115 // Parse command line arguments AFTER the modules have been loaded (static code!)116 CommandLineParser::parseCommandLine(cmdLine);117 118 66 // Set configurable paths like log, config and media 119 67 this->pathConfig_->setConfigurablePaths(); 120 121 // create a signal handler (only active for Linux)122 // This call is placed as soon as possible, but after the directories are set123 this->signalHandler_.reset(new SignalHandler());124 this->signalHandler_->doCatch(PathConfig::getExecutablePathString(), PathConfig::getLogPathString() + "orxonox_crash.log");125 68 126 69 // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% (Windows) was used 127 70 OutputHandler::getInstance().setLogPath(PathConfig::getLogPathString()); 128 71 129 // Parse additional options file now that we know its path130 CommandLineParser::parseFile();131 132 72 #ifdef ORXONOX_PLATFORM_WINDOWS 133 73 // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump 134 // do this after ogre has initialised. Somehow Ogre changes the settings again (not through 135 // the timer though). 136 int limitToCPU = CommandLineParser::getValue("limitToCPU"); 74 int limitToCPU = 0;//CommandLineParser::getValue("limitToCPU"); 137 75 if (limitToCPU > 0) 138 76 setThreadAffinity(static_cast<unsigned int>(limitToCPU)); 139 77 #endif 140 78 141 // Manage ini files and set the default settings file (usually orxonox.ini)142 this->configFileManager_.reset(new ConfigFileManager());143 this->configFileManager_->setFilename(ConfigFileType::Settings,144 CommandLineParser::getValue("settingsFile").getString());145 146 // Required as well for the config values147 this->languageInstance_.reset(new Language());148 149 // Do this soon after the ConfigFileManager has been created to open up the150 // possibility to configure everything below here151 ClassIdentifier<Core>::getIdentifier("Core")->initialiseObject(this, "Core", true);152 this->setConfigValues();153 154 // create persistent io console155 if (CommandLineParser::getValue("noIOConsole").getBool())156 {157 ModifyConfigValue(bStartIOConsole_, tset, false);158 }159 if (this->bStartIOConsole_)160 this->ioConsole_.reset(new IOConsole());161 162 // creates the class hierarchy for all classes with factories163 Identifier::createClassHierarchy();164 165 // Load OGRE excluding the renderer and the render window166 this->graphicsManager_.reset(new GraphicsManager(false));167 168 // initialise Tcl169 this->tclBind_.reset(new TclBind(PathConfig::getDataPathString()));170 this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));171 172 // Create singletons that always exist (in other libraries)173 this->rootScope_.reset(new Scope<ScopeID::Root>());174 175 79 // Generate documentation instead of normal run? 176 80 std::string docFilename; 177 CommandLineParser::getValue("generateDoc", &docFilename);81 //CommandLineParser::getValue("generateDoc", &docFilename); 178 82 if (!docFilename.empty()) 179 83 { … … 181 85 if (docFile.is_open()) 182 86 { 183 CommandLineParser::generateDoc(docFile);87 //CommandLineParser::generateDoc(docFile); 184 88 docFile.close(); 185 89 } … … 191 95 /** 192 96 @brief 193 All destruction code is handled by scoped_ptrs and ScopeGuards.97 All destruction code is handled by QScopedPointers 194 98 */ 195 99 Core::~Core() 196 100 { 197 // Remove us from the object lists again to avoid problems when destroying them198 this->unregisterObject();199 101 } 200 102 … … 207 109 const unsigned int defaultLevelLogFile = 4; 208 110 #endif 111 /* 209 112 SetConfigValueExternal(softDebugLevelLogFile_, "OutputHandler", "softDebugLevelLogFile", defaultLevelLogFile) 210 113 .description("The maximum level of debug output shown in the log file"); … … 219 122 SetConfigValue(bStartIOConsole_, true) 220 123 .description("Set to false if you don't want to use the IOConsole (for Lua debugging for instance)"); 221 } 222 223 //! Callback function if the language has changed. 224 void Core::languageChanged() 225 { 226 // Read the translation file after the language was configured 227 Language::getInstance().readTranslatedLanguageFile(); 124 */ 228 125 } 229 126 … … 237 134 bInitialized = true; 238 135 } 239 }240 241 void Core::loadGraphics()242 {243 // Any exception should trigger this, even in upgradeToGraphics (see its remarks)244 Loki::ScopeGuard unloader = Loki::MakeObjGuard(*this, &Core::unloadGraphics);245 246 // Upgrade OGRE to receive a render window247 try248 {249 graphicsManager_->upgradeToGraphics();250 }251 catch (...)252 {253 // Recovery from this is very difficult. It requires to completely254 // destroy Ogre related objects and load again (without graphics).255 // However since Ogre 1.7 there seems to be a problem when Ogre256 // throws an exception and the graphics engine then gets destroyed257 // and reloaded between throw and catch (access violation in MSVC).258 // That's why we abort completely and only display the exception.259 COUT(0) << "An exception occurred during upgrade to graphics. "260 << "That is unrecoverable. The message was:" << endl261 << Exception::handleMessage() << endl;262 abort();263 }264 265 // Calls the InputManager which sets up the input devices.266 inputManager_.reset(new InputManager());267 268 // Load the CEGUI interface269 guiManager_.reset(new GUIManager(inputManager_->getMousePosition()));270 271 bGraphicsLoaded_ = true;272 GameMode::bShowsGraphics_s = true;273 274 // Load some sort of a debug overlay (only denoted by its name, "debug.oxo")275 graphicsManager_->loadDebugOverlay();276 277 // Create singletons associated with graphics (in other libraries)278 graphicsScope_.reset(new Scope<ScopeID::Graphics>());279 280 unloader.Dismiss();281 }282 283 void Core::unloadGraphics()284 {285 this->graphicsScope_.reset();286 this->guiManager_.reset();287 this->inputManager_.reset();288 this->graphicsManager_.reset();289 290 // Load Ogre::Root again, but without the render system291 try292 { this->graphicsManager_.reset(new GraphicsManager(false)); }293 catch (...)294 {295 COUT(0) << "An exception occurred during 'unloadGraphics':" << Exception::handleMessage() << std::endl296 << "Another exception might be being handled which may lead to undefined behaviour!" << std::endl297 << "Terminating the program." << std::endl;298 abort();299 }300 301 bGraphicsLoaded_ = false;302 GameMode::bShowsGraphics_s = false;303 }304 305 //! Sets the language in the config-file back to the default.306 void Core::resetLanguage()307 {308 ResetConfigValue(language_);309 136 } 310 137 … … 354 181 #endif 355 182 } 356 357 void Core::preUpdate(const Clock& time)358 {359 // Update singletons before general ticking360 ScopedSingletonManager::preUpdate<ScopeID::Root>(time);361 if (this->bGraphicsLoaded_)362 {363 // Process input events364 this->inputManager_->preUpdate(time);365 // Update GUI366 this->guiManager_->preUpdate(time);367 // Update singletons before general ticking368 ScopedSingletonManager::preUpdate<ScopeID::Graphics>(time);369 }370 // Process console events and status line371 if (this->ioConsole_ != NULL)372 this->ioConsole_->preUpdate(time);373 // Process thread commands374 this->tclThreadManager_->preUpdate(time);375 }376 377 void Core::postUpdate(const Clock& time)378 {379 // Update singletons just before rendering380 ScopedSingletonManager::postUpdate<ScopeID::Root>(time);381 if (this->bGraphicsLoaded_)382 {383 // Update singletons just before rendering384 ScopedSingletonManager::postUpdate<ScopeID::Graphics>(time);385 // Render (doesn't throw)386 this->graphicsManager_->postUpdate(time);387 }388 }389 183 } -
sandbox_qt/src/libraries/core/Core.h
r7401 r7421 45 45 46 46 #include <string> 47 #include < boost/scoped_ptr.hpp>47 #include <QScopedPointer> 48 48 #include <loki/ScopeGuard.h> 49 49 50 50 #include "util/Singleton.h" 51 #include " OrxonoxClass.h"51 #include "PathConfig.h" 52 52 53 53 namespace orxonox … … 59 59 You should only create this singleton once because it destroys the identifiers! 60 60 */ 61 class _CoreExport Core : public Singleton<Core> , public OrxonoxClass61 class _CoreExport Core : public Singleton<Core> 62 62 { 63 63 typedef Loki::ScopeGuardImpl0<void (*)()> SimpleScopeGuard; … … 78 78 void setConfigValues(); 79 79 80 //! Returns the configured language.81 const std::string& getLanguage()82 { return this->language_; }83 void resetLanguage();84 85 80 private: 86 81 Core(const Core&); //!< Don't use (undefined symbol) 87 82 88 void languageChanged();89 83 void initRandomNumberGenerator(); 90 84 91 void preUpdate(const Clock& time); 92 void postUpdate(const Clock& time); 93 94 void loadGraphics(); 95 void unloadGraphics(); 85 void update() {} 96 86 97 87 void setThreadAffinity(int limitToCPU); 98 88 // MANAGED SINGLETONS/OBJECTS 99 89 // Mind the order for the destruction! 100 scoped_ptr<PathConfig> pathConfig_; 101 scoped_ptr<DynLibManager> dynLibManager_; 102 scoped_ptr<SignalHandler> signalHandler_; 103 SimpleScopeGuard identifierDestroyer_; 104 SimpleScopeGuard consoleCommandDestroyer_; 105 scoped_ptr<ConfigFileManager> configFileManager_; 106 scoped_ptr<Language> languageInstance_; 107 scoped_ptr<IOConsole> ioConsole_; 108 scoped_ptr<TclBind> tclBind_; 109 scoped_ptr<TclThreadManager> tclThreadManager_; 110 scoped_ptr<Scope<ScopeID::Root> > rootScope_; 111 // graphical 112 scoped_ptr<GraphicsManager> graphicsManager_; //!< Interface to OGRE 113 scoped_ptr<InputManager> inputManager_; //!< Interface to OIS 114 scoped_ptr<GUIManager> guiManager_; //!< Interface to GUI 115 scoped_ptr<Scope<ScopeID::Graphics> > graphicsScope_; 90 QScopedPointer<PathConfig> pathConfig_; 116 91 117 bool bGraphicsLoaded_;118 92 int softDebugLevelLogFile_; //!< The debug level for the log file (belongs to OutputHandler) 119 std::string language_; //!< The language120 93 bool bInitRandomNumberGenerator_; //!< If true, srand(time(0)) is called 121 bool bStartIOConsole_; //!< Set to false if you don't want to use the IOConsole122 94 123 95 static Core* singletonPtr_s; -
sandbox_qt/src/libraries/core/CorePrereqs.h
r7284 r7421 37 37 38 38 #include "OrxonoxConfig.h" 39 #include <boost/version.hpp>40 39 41 40 //----------------------------------------------------------------------- … … 63 62 //----------------------------------------------------------------------- 64 63 65 namespace orxonox66 {67 static const uint32_t OBJECTID_UNKNOWN = static_cast<uint32_t>(-1);68 }69 70 64 //----------------------------------------------------------------------- 71 65 // Enums 72 66 //----------------------------------------------------------------------- 73 74 namespace orxonox75 {76 namespace XMLPort77 {78 enum Mode79 {80 NOP,81 LoadObject,82 SaveObject,83 ExpandObject84 };85 }86 87 namespace ConfigFileType88 {89 enum Value90 {91 Settings,92 JoyStickCalibration,93 CommandHistory94 // Don't forget to adjust the array size in the ConfigFileManager when adding a new entry here!95 };96 }97 98 namespace KeybindMode99 {100 enum Value101 {102 OnPress,103 OnHold,104 OnRelease,105 None106 };107 };108 }109 67 110 68 //----------------------------------------------------------------------- … … 114 72 namespace orxonox 115 73 { 116 typedef std::string LanguageEntryLabel;117 118 template <class T, class U>119 T orxonox_cast(U*);120 121 class BaseObject;122 template <class T>123 class ClassFactory;124 template <class T>125 class ClassIdentifier;126 class ClassTreeMask;127 class ClassTreeMaskIterator;128 class ClassTreeMaskNode;129 class ClassTreeMaskObjectIterator;130 class CommandLineParser;131 class CommandLineArgument;132 class ConfigFile;133 class ConfigFileEntry;134 class ConfigFileEntryComment;135 class ConfigFileEntryValue;136 class ConfigFileManager;137 class ConfigFileSection;138 class ConfigValueContainer;139 74 class Core; 140 class DynLib;141 class DynLibManager;142 struct Event;143 class EventState;144 class Factory;145 75 class Game; 146 class GameState;147 struct GameStateInfo;148 struct GameStateTreeNode;149 class GraphicsManager;150 class GUIManager;151 class Identifier;152 template <class T>153 class Iterator;154 class Language;155 class LuaFunctor;156 class LuaState;157 class MemoryArchive;158 class MemoryArchiveFactory;159 class MetaObjectList;160 class MetaObjectListElement;161 class Namespace;162 class NamespaceNode;163 template <class T>164 class ObjectList;165 class ObjectListBase;166 class ObjectListBaseElement;167 template <class T>168 class ObjectListElement;169 template <class T>170 class ObjectListIterator;171 class OgreWindowEventListener;172 class OrxonoxClass;173 76 class PathConfig; 174 struct ResourceInfo;175 class SettingsConfigFile;176 template <class T>177 class SmartPtr;178 template <class T>179 class SubclassIdentifier;180 class Template;181 class Thread;182 class ThreadPool;183 template <class T>184 class WeakPtr;185 class WindowEventListener;186 class XMLFile;187 class XMLNameListener;188 template <class T, class O>189 class XMLPortClassObjectContainer;190 template <class T>191 class XMLPortClassParamContainer;192 class XMLPortObjectContainer;193 class XMLPortParamContainer;194 195 // Command196 class ArgumentCompleter;197 class ArgumentCompletionListElement;198 class CommandEvaluation;199 class ConsoleCommand;200 class Executor;201 template <class T>202 class ExecutorMember;203 class ExecutorStatic;204 class Functor;205 template <class O>206 class FunctorMember;207 typedef FunctorMember<void> FunctorStatic;208 template <class F, class O>209 class FunctorPointer;210 class IOConsole;211 class IRC;212 class Shell;213 class ShellListener;214 class TclBind;215 struct TclInterpreterBundle;216 template <class T>217 class TclThreadList;218 class TclThreadManager;219 220 // Input221 class BaseCommand;222 class BufferedParamCommand;223 class Button;224 class HalfAxis;225 class InputBuffer;226 class InputDevice;227 template <class Traits>228 class InputDeviceTemplated;229 class InputHandler;230 class InputManager;231 class InputState;232 struct InputStatePriority;233 class JoyStickQuantityListener;234 class JoyStick;235 class KeyBinder;236 class KeyBinderManager;237 class Keyboard;238 class KeyDetector;239 class KeyEvent;240 class Mouse;241 class ParamCommand;242 class SimpleCommand;243 }244 245 #include "command/FunctorPtr.h"246 #include "command/ExecutorPtr.h"247 248 // CppTcl249 namespace Tcl250 {251 class interpreter;252 class object;253 }254 255 // Boost256 namespace boost257 {258 #if (BOOST_VERSION < 104400)259 namespace filesystem260 {261 struct path_traits;262 template <class String, class Traits> class basic_path;263 typedef basic_path<std::string, path_traits> path;264 }265 #else266 namespace filesystem2267 {268 struct path_traits;269 template <class String, class Traits> class basic_path;270 typedef basic_path<std::string, path_traits> path;271 }272 namespace filesystem273 {274 using filesystem2::basic_path;275 using filesystem2::path_traits;276 using filesystem2::path;277 }278 #endif279 class thread;280 class mutex;281 class shared_mutex;282 class condition_variable;283 }284 285 // Ogre286 namespace Ogre287 {288 class DataStream;289 template <class T> class SharedPtr;290 typedef SharedPtr<DataStream> DataStreamPtr;291 }292 namespace orxonox293 {294 // Import the Ogre::DataStream295 using Ogre::DataStream;296 using Ogre::DataStreamPtr;297 }298 299 // CEGUI300 namespace CEGUI301 {302 class DefaultLogger;303 class Logger;304 class LuaScriptModule;305 306 class OgreCEGUIRenderer;307 class OgreCEGUIResourceProvider;308 class OgreCEGUITexture;309 }310 311 // Lua312 struct lua_State;313 314 // TinyXML and TinyXML++315 class TiXmlString;316 class TiXmlOutStream;317 class TiXmlNode;318 class TiXmlHandle;319 class TiXmlDocument;320 class TiXmlElement;321 class TiXmlComment;322 class TiXmlUnknown;323 class TiXmlAttribute;324 class TiXmlText;325 class TiXmlDeclaration;326 class TiXmlParsingData;327 namespace ticpp328 {329 class Document;330 class Element;331 class Declaration;332 class StylesheetReference;333 class Text;334 class Comment;335 class Attribute;336 }337 namespace orxonox338 {339 using ticpp::Element;340 77 } 341 78 -
sandbox_qt/src/libraries/core/Game.cc
r7284 r7421 36 36 37 37 #include <exception> 38 #include <boost/weak_ptr.hpp>39 #include <loki/ScopeGuard.h>40 38 41 #include "util/Clock.h"42 39 #include "util/Debug.h" 43 40 #include "util/Exception.h" 44 41 #include "util/Sleep.h" 45 #include "util/SubString.h"46 #include "CommandLineParser.h"47 42 #include "Core.h" 48 #include "CoreIncludes.h"49 #include "ConfigValueIncludes.h"50 #include "GameMode.h"51 #include "GameState.h"52 #include "GUIManager.h"53 #include "command/ConsoleCommand.h"54 43 55 44 namespace orxonox 56 45 { 57 static void stop_game()58 { Game::getInstance().stop(); }59 SetConsoleCommand("exit", &stop_game);60 static void printFPS()61 { COUT(0) << Game::getInstance().getAvgFPS() << std::endl; }62 SetConsoleCommand("printFPS", &printFPS);63 static void printTickTime()64 { COUT(0) << Game::getInstance().getAvgTickTime() << std::endl; }65 SetConsoleCommand("printTickTime", &printTickTime);66 67 std::map<std::string, GameStateInfo> Game::gameStateDeclarations_s;68 46 Game* Game::singletonPtr_s = 0; 69 47 70 //! Represents one node of the game state tree.71 struct GameStateTreeNode72 {73 std::string name_;74 weak_ptr<GameStateTreeNode> parent_;75 std::vector<shared_ptr<GameStateTreeNode> > children_;76 };77 78 48 Game::Game(const std::string& cmdLine) 79 // Destroy factories before the Core!80 : gsFactoryDestroyer_(Game::GameStateFactory::getFactories(), &std::map<std::string, shared_ptr<GameStateFactory> >::clear)81 49 { 82 50 this->bAbort_ = false; 83 bChangingState_ = false;84 85 #ifdef ORXONOX_PLATFORM_WINDOWS86 minimumSleepTime_ = 1000/*us*/;87 #else88 minimumSleepTime_ = 0/*us*/;89 #endif90 91 // reset statistics92 this->statisticsStartTime_ = 0;93 this->statisticsTickTimes_.clear();94 this->periodTickTime_ = 0;95 this->periodTime_ = 0;96 this->avgFPS_ = 0.0f;97 this->avgTickTime_ = 0.0f;98 this->excessSleepTime_ = 0;99 100 // Create an empty root state101 this->declareGameState<GameState>("GameState", "emptyRootGameState", true, false);102 103 // Set up a basic clock to keep time104 this->gameClock_.reset(new Clock());105 51 106 52 // Create the Core 107 53 this->core_.reset(new Core(cmdLine)); 108 109 // Do this after the Core creation!110 ClassIdentifier<Game>::getIdentifier("Game")->initialiseObject(this, "Game", true);111 this->setConfigValues();112 113 // After the core has been created, we can safely instantiate the GameStates that don't require graphics114 for (std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.begin();115 it != gameStateDeclarations_s.end(); ++it)116 {117 if (!it->second.bGraphicsMode)118 constructedStates_[it->second.stateName] = GameStateFactory::fabricate(it->second);119 }120 121 // The empty root state is ALWAYS loaded!122 this->rootStateNode_ = shared_ptr<GameStateTreeNode>(new GameStateTreeNode());123 this->rootStateNode_->name_ = "emptyRootGameState";124 this->loadedTopStateNode_ = this->rootStateNode_;125 this->loadedStates_.push_back(this->getState(rootStateNode_->name_));126 54 } 127 55 128 56 /** 129 57 @brief 130 All destruction code is handled by scoped_ptrs and SimpleScopeGuards.58 All destruction code is handled by QScopedPointers. 131 59 */ 132 60 Game::~Game() 133 61 { 134 // Remove us from the object lists again to avoid problems when destroying them135 this->unregisterObject();136 62 } 137 63 138 64 void Game::setConfigValues() 139 65 { 66 /* 140 67 SetConfigValue(statisticsRefreshCycle_, 250000) 141 68 .description("Sets the time in microseconds interval at which average fps, etc. get updated."); … … 144 71 SetConfigValue(fpsLimit_, 50) 145 72 .description("Sets the desired frame rate (0 for no limit)."); 73 */ 146 74 } 147 75 … … 149 77 @brief 150 78 Main loop of the orxonox game. 151 @note152 We use the Ogre::Timer to measure time since it uses the most precise153 method an any platform (however the windows timer lacks time when under154 heavy kernel load!).155 79 */ 156 80 void Game::run() 157 81 { 158 if (this->requestedStateNodes_.empty()) 159 COUT(0) << "Warning: Starting game without requesting GameState. This automatically terminates the program." << std::endl; 160 161 // START GAME 162 // first delta time should be about 0 seconds 163 this->gameClock_->capture(); 164 // A first item is required for the fps limiter 165 StatisticsTickInfo tickInfo = {0, 0}; 166 statisticsTickTimes_.push_back(tickInfo); 167 while (!this->bAbort_ && (!this->loadedStates_.empty() || this->requestedStateNodes_.size() > 0)) 82 while (!this->bAbort_) 168 83 { 169 // Generate the dt170 this->gameClock_->capture();171 172 // Statistics init173 StatisticsTickInfo tickInfo = {gameClock_->getMicroseconds(), 0};174 statisticsTickTimes_.push_back(tickInfo);175 this->periodTime_ += this->gameClock_->getDeltaTimeMicroseconds();176 177 // Update the GameState stack if required178 this->updateGameStateStack();179 180 // Core preUpdate181 84 try 182 { this->core_->preUpdate(*this->gameClock_); } 183 catch (...) 184 { 185 COUT(0) << "An exception occurred in the Core preUpdate: " << Exception::handleMessage() << std::endl; 186 COUT(0) << "This should really never happen! Closing the program." << std::endl; 187 this->stop(); 188 break; 189 } 190 191 // Update the GameStates bottom up in the stack 192 this->updateGameStates(); 193 194 // Core postUpdate 195 try 196 { this->core_->postUpdate(*this->gameClock_); } 85 { this->core_->update(); } 197 86 catch (...) 198 87 { … … 202 91 break; 203 92 } 204 205 // Evaluate statistics206 this->updateStatistics();207 208 // Limit frame rate209 this->updateFPSLimiter();210 93 } 211 212 // UNLOAD all remaining states213 while (this->loadedStates_.size() > 1)214 this->unloadState(this->loadedStates_.back()->getName());215 this->loadedTopStateNode_ = this->rootStateNode_;216 this->requestedStateNodes_.clear();217 }218 219 void Game::updateGameStateStack()220 {221 while (this->requestedStateNodes_.size() > 0)222 {223 shared_ptr<GameStateTreeNode> requestedStateNode = this->requestedStateNodes_.front();224 assert(this->loadedTopStateNode_);225 if (!this->loadedTopStateNode_->parent_.expired() && requestedStateNode == this->loadedTopStateNode_->parent_.lock())226 this->unloadState(loadedTopStateNode_->name_);227 else // has to be child228 {229 try230 {231 this->loadState(requestedStateNode->name_);232 }233 catch (...)234 {235 COUT(1) << "Error: Loading GameState '" << requestedStateNode->name_ << "' failed: " << Exception::handleMessage() << std::endl;236 // All scheduled operations have now been rendered inert --> flush them and issue a warning237 if (this->requestedStateNodes_.size() > 1)238 COUT(4) << "All " << this->requestedStateNodes_.size() - 1 << " scheduled transitions have been ignored." << std::endl;239 this->requestedStateNodes_.clear();240 break;241 }242 }243 this->loadedTopStateNode_ = requestedStateNode;244 this->requestedStateNodes_.erase(this->requestedStateNodes_.begin());245 }246 }247 248 void Game::updateGameStates()249 {250 // Note: The first element is the empty root state, which doesn't need ticking251 for (GameStateVector::const_iterator it = this->loadedStates_.begin() + 1;252 it != this->loadedStates_.end(); ++it)253 {254 try255 {256 // Add tick time for most of the states257 uint64_t timeBeforeTick = 0;258 if ((*it)->getInfo().bIgnoreTickTime)259 timeBeforeTick = this->gameClock_->getRealMicroseconds();260 (*it)->update(*this->gameClock_);261 if ((*it)->getInfo().bIgnoreTickTime)262 this->subtractTickTime(static_cast<int32_t>(this->gameClock_->getRealMicroseconds() - timeBeforeTick));263 }264 catch (...)265 {266 COUT(1) << "An exception occurred while updating '" << (*it)->getName() << "': " << Exception::handleMessage() << std::endl;267 COUT(1) << "This should really never happen!" << std::endl;268 COUT(1) << "Unloading all GameStates depending on the one that crashed." << std::endl;269 shared_ptr<GameStateTreeNode> current = this->loadedTopStateNode_;270 while (current->name_ != (*it)->getName() && current)271 current = current->parent_.lock();272 if (current && current->parent_.lock())273 this->requestState(current->parent_.lock()->name_);274 else275 this->stop();276 break;277 }278 }279 }280 281 void Game::updateStatistics()282 {283 // Add the tick time of this frame (rendering time has already been subtracted)284 uint64_t currentTime = gameClock_->getMicroseconds();285 uint64_t currentRealTime = gameClock_->getRealMicroseconds();286 this->statisticsTickTimes_.back().tickLength += (uint32_t)(currentRealTime - currentTime);287 this->periodTickTime_ += (uint32_t)(currentRealTime - currentTime);288 if (this->periodTime_ > this->statisticsRefreshCycle_)289 {290 std::list<StatisticsTickInfo>::iterator it = this->statisticsTickTimes_.begin();291 assert(it != this->statisticsTickTimes_.end());292 int64_t lastTime = currentTime - this->statisticsAvgLength_;293 if (static_cast<int64_t>(it->tickTime) < lastTime)294 {295 do296 {297 assert(this->periodTickTime_ >= it->tickLength);298 this->periodTickTime_ -= it->tickLength;299 ++it;300 assert(it != this->statisticsTickTimes_.end());301 } while (static_cast<int64_t>(it->tickTime) < lastTime);302 this->statisticsTickTimes_.erase(this->statisticsTickTimes_.begin(), it);303 }304 305 uint32_t framesPerPeriod = this->statisticsTickTimes_.size();306 // Why minus 1? No idea, but otherwise the fps rate is always (from 10 to 200!) one frame too low307 this->avgFPS_ = -1 + static_cast<float>(framesPerPeriod) / (currentTime - this->statisticsTickTimes_.front().tickTime) * 1000000.0f;308 this->avgTickTime_ = static_cast<float>(this->periodTickTime_) / framesPerPeriod / 1000.0f;309 310 this->periodTime_ -= this->statisticsRefreshCycle_;311 }312 }313 314 void Game::updateFPSLimiter()315 {316 uint64_t nextTime = gameClock_->getMicroseconds() - excessSleepTime_ + static_cast<uint32_t>(1000000.0f / fpsLimit_);317 uint64_t currentRealTime = gameClock_->getRealMicroseconds();318 while (currentRealTime < nextTime - minimumSleepTime_)319 {320 usleep((unsigned long)(nextTime - currentRealTime));321 currentRealTime = gameClock_->getRealMicroseconds();322 }323 // Integrate excess to avoid steady state error324 excessSleepTime_ = (int)(currentRealTime - nextTime);325 // Anti windup326 if (excessSleepTime_ > 50000) // 20ms is about the maximum time Windows would sleep for too long327 excessSleepTime_ = 50000;328 94 } 329 95 … … 332 98 this->bAbort_ = true; 333 99 } 334 335 void Game::subtractTickTime(int32_t length)336 {337 assert(!this->statisticsTickTimes_.empty());338 this->statisticsTickTimes_.back().tickLength -= length;339 this->periodTickTime_ -= length;340 }341 342 343 /***** GameState related *****/344 345 void Game::requestState(const std::string& name)346 {347 if (!this->checkState(name))348 {349 COUT(2) << "Warning: GameState named '" << name << "' doesn't exist!" << std::endl;350 return;351 }352 353 if (this->bChangingState_)354 {355 COUT(2) << "Warning: Requesting GameStates while loading/unloading a GameState is illegal! Ignoring." << std::endl;356 return;357 }358 359 shared_ptr<GameStateTreeNode> lastRequestedNode;360 if (this->requestedStateNodes_.empty())361 lastRequestedNode = this->loadedTopStateNode_;362 else363 lastRequestedNode = this->requestedStateNodes_.back();364 if (name == lastRequestedNode->name_)365 {366 COUT(2) << "Warning: Requesting the currently active state! Ignoring." << std::endl;367 return;368 }369 370 // Check children first371 std::vector<shared_ptr<GameStateTreeNode> > requestedNodes;372 for (unsigned int i = 0; i < lastRequestedNode->children_.size(); ++i)373 {374 if (lastRequestedNode->children_[i]->name_ == name)375 {376 requestedNodes.push_back(lastRequestedNode->children_[i]);377 break;378 }379 }380 381 if (requestedNodes.empty())382 {383 // Check parent and all its grand parents384 shared_ptr<GameStateTreeNode> currentNode = lastRequestedNode;385 while (currentNode != NULL)386 {387 if (currentNode->name_ == name)388 break;389 currentNode = currentNode->parent_.lock();390 requestedNodes.push_back(currentNode);391 }392 if (currentNode == NULL)393 requestedNodes.clear();394 }395 396 if (requestedNodes.empty())397 COUT(1) << "Error: Requested GameState transition is not allowed. Ignoring." << std::endl;398 else399 this->requestedStateNodes_.insert(requestedStateNodes_.end(), requestedNodes.begin(), requestedNodes.end());400 }401 402 void Game::requestStates(const std::string& names)403 {404 SubString tokens(names, ",;", " ");405 for (unsigned int i = 0; i < tokens.size(); ++i)406 this->requestState(tokens[i]);407 }408 409 void Game::popState()410 {411 shared_ptr<GameStateTreeNode> lastRequestedNode;412 if (this->requestedStateNodes_.empty())413 lastRequestedNode = this->loadedTopStateNode_;414 else415 lastRequestedNode = this->requestedStateNodes_.back();416 if (lastRequestedNode != this->rootStateNode_)417 this->requestState(lastRequestedNode->parent_.lock()->name_);418 else419 COUT(2) << "Warning: Can't pop the internal dummy root GameState" << std::endl;420 }421 422 shared_ptr<GameState> Game::getState(const std::string& name)423 {424 GameStateMap::const_iterator it = constructedStates_.find(name);425 if (it != constructedStates_.end())426 return it->second;427 else428 {429 std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.find(name);430 if (it != gameStateDeclarations_s.end())431 COUT(1) << "Error: GameState '" << name << "' has not yet been loaded." << std::endl;432 else433 COUT(1) << "Error: Could not find GameState '" << name << "'." << std::endl;434 return shared_ptr<GameState>();435 }436 }437 438 void Game::setStateHierarchy(const std::string& str)439 {440 // Split string into pieces of the form whitespacesText441 std::vector<std::pair<std::string, int> > stateStrings;442 size_t pos = 0;443 size_t startPos = 0;444 while (pos < str.size())445 {446 int indentation = 0;447 while (pos < str.size() && str[pos] == ' ')448 ++indentation, ++pos;449 startPos = pos;450 while (pos < str.size() && str[pos] != ' ')451 ++pos;452 stateStrings.push_back(std::make_pair(str.substr(startPos, pos - startPos), indentation));453 }454 if (stateStrings.empty())455 ThrowException(GameState, "Emtpy GameState hierarchy provided, terminating.");456 // Add element with large identation to detect the last with just an iterator457 stateStrings.push_back(std::make_pair("", -1));458 459 // Parse elements recursively460 std::vector<std::pair<std::string, int> >::const_iterator begin = stateStrings.begin();461 parseStates(begin, this->rootStateNode_);462 }463 464 /*** Internal ***/465 466 void Game::parseStates(std::vector<std::pair<std::string, int> >::const_iterator& it, shared_ptr<GameStateTreeNode> currentNode)467 {468 SubString tokens(it->first, ",");469 std::vector<std::pair<std::string, int> >::const_iterator startIt = it;470 471 for (unsigned int i = 0; i < tokens.size(); ++i)472 {473 it = startIt; // Reset iterator to the beginning of the sub tree474 if (!this->checkState(tokens[i]))475 ThrowException(GameState, "GameState with name '" << tokens[i] << "' not found!");476 if (tokens[i] == this->rootStateNode_->name_)477 ThrowException(GameState, "You shouldn't use 'emptyRootGameState' in the hierarchy...");478 shared_ptr<GameStateTreeNode> node(new GameStateTreeNode());479 node->name_ = tokens[i];480 node->parent_ = currentNode;481 currentNode->children_.push_back(node);482 483 int currentLevel = it->second;484 ++it;485 while (it->second != -1)486 {487 if (it->second <= currentLevel)488 break;489 else if (it->second == currentLevel + 1)490 parseStates(it, node);491 else492 ThrowException(GameState, "Indentation error while parsing the hierarchy.");493 }494 }495 }496 497 void Game::loadGraphics()498 {499 if (!GameMode::showsGraphics())500 {501 core_->loadGraphics();502 Loki::ScopeGuard graphicsUnloader = Loki::MakeObjGuard(*this, &Game::unloadGraphics);503 504 // Construct all the GameStates that require graphics505 for (std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.begin();506 it != gameStateDeclarations_s.end(); ++it)507 {508 if (it->second.bGraphicsMode)509 {510 // Game state loading failure is serious --> don't catch511 shared_ptr<GameState> gameState = GameStateFactory::fabricate(it->second);512 if (!constructedStates_.insert(std::make_pair(513 it->second.stateName, gameState)).second)514 assert(false); // GameState was already created!515 }516 }517 graphicsUnloader.Dismiss();518 }519 }520 521 void Game::unloadGraphics()522 {523 if (GameMode::showsGraphics())524 {525 // Destroy all the GameStates that require graphics526 for (GameStateMap::iterator it = constructedStates_.begin(); it != constructedStates_.end();)527 {528 if (it->second->getInfo().bGraphicsMode)529 constructedStates_.erase(it++);530 else531 ++it;532 }533 534 core_->unloadGraphics();535 }536 }537 538 bool Game::checkState(const std::string& name) const539 {540 std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.find(name);541 if (it == gameStateDeclarations_s.end())542 return false;543 else544 return true;545 }546 547 void Game::loadState(const std::string& name)548 {549 this->bChangingState_ = true;550 LOKI_ON_BLOCK_EXIT_OBJ(*this, &Game::resetChangingState);551 552 // If state requires graphics, load it553 Loki::ScopeGuard graphicsUnloader = Loki::MakeObjGuard(*this, &Game::unloadGraphics);554 if (gameStateDeclarations_s[name].bGraphicsMode && !GameMode::showsGraphics())555 this->loadGraphics();556 else557 graphicsUnloader.Dismiss();558 559 shared_ptr<GameState> state = this->getState(name);560 state->activateInternal();561 if (!this->loadedStates_.empty())562 this->loadedStates_.back()->activity_.topState = false;563 this->loadedStates_.push_back(state);564 state->activity_.topState = true;565 566 graphicsUnloader.Dismiss();567 }568 569 void Game::unloadState(const std::string& name)570 {571 this->bChangingState_ = true;572 try573 {574 shared_ptr<GameState> state = this->getState(name);575 state->activity_.topState = false;576 this->loadedStates_.pop_back();577 if (!this->loadedStates_.empty())578 this->loadedStates_.back()->activity_.topState = true;579 state->deactivateInternal();580 }581 catch (...)582 {583 COUT(2) << "Warning: Unloading GameState '" << name << "' threw an exception: " << Exception::handleMessage() << std::endl;584 COUT(2) << " There might be potential resource leaks involved! To avoid this, improve exception-safety." << std::endl;585 }586 // Check if graphics is still required587 if (!bAbort_)588 {589 bool graphicsRequired = false;590 for (unsigned i = 0; i < loadedStates_.size(); ++i)591 graphicsRequired |= loadedStates_[i]->getInfo().bGraphicsMode;592 if (!graphicsRequired)593 this->unloadGraphics();594 }595 this->bChangingState_ = false;596 }597 598 /*static*/ std::map<std::string, shared_ptr<Game::GameStateFactory> >& Game::GameStateFactory::getFactories()599 {600 static std::map<std::string, shared_ptr<GameStateFactory> > factories;601 return factories;602 }603 604 /*static*/ shared_ptr<GameState> Game::GameStateFactory::fabricate(const GameStateInfo& info)605 {606 std::map<std::string, shared_ptr<Game::GameStateFactory> >::const_iterator it = getFactories().find(info.className);607 assert(it != getFactories().end());608 return it->second->fabricateInternal(info);609 }610 100 } -
sandbox_qt/src/libraries/core/Game.h
r7401 r7421 39 39 #include "CorePrereqs.h" 40 40 41 #include <cassert>42 #include <list>43 #include <map>44 41 #include <string> 45 #include <vector> 46 #include <boost/shared_ptr.hpp> 47 #include <boost/scoped_ptr.hpp> 48 #include <boost/preprocessor/cat.hpp> 49 #include <loki/ScopeGuard.h> 42 #include <QScopedPointer> 43 #include "util/Singleton.h" 50 44 51 #include "util/Debug.h"52 #include "util/Singleton.h"53 #include "OrxonoxClass.h"54 55 /**56 @brief57 Adds a new GameState to the Game. The second parameter is the name as string58 and every following paramter is a constructor argument (which is usually non existent)59 */60 #define DeclareGameState(className, stateName, bIgnoreTickTime, bGraphicsMode) \61 static bool BOOST_PP_CAT(bGameStateDummy_##className, __LINE__) = orxonox::Game::declareGameState<className>(#className, stateName, bIgnoreTickTime, bGraphicsMode)62 // tolua_begin63 45 namespace orxonox 64 46 { 65 // tolua_end66 67 //! Helper object required before GameStates are being constructed68 struct GameStateInfo69 {70 std::string stateName;71 std::string className;72 bool bIgnoreTickTime;73 bool bGraphicsMode;74 };75 76 47 /** 77 48 @brief … … 80 51 You should only create this singleton once because it owns the Core class! (see remark there) 81 52 */ 82 // tolua_begin 83 class _CoreExport Game 84 // tolua_end 85 : public Singleton<Game>, public OrxonoxClass 86 { // tolua_export 53 class _CoreExport Game : public Singleton<Game> 54 { 87 55 friend class Singleton<Game>; 88 typedef std::vector<shared_ptr<GameState> > GameStateVector;89 typedef std::map<std::string, shared_ptr<GameState> > GameStateMap;90 typedef shared_ptr<GameStateTreeNode> GameStateTreeNodePtr;91 56 92 57 public: … … 96 61 void setConfigValues(); 97 62 98 void setStateHierarchy(const std::string& str);99 shared_ptr<GameState> getState(const std::string& name);100 101 63 void run(); 102 64 void stop(); 103 65 104 static Game& getInstance(){ return Singleton<Game>::getInstance(); } // tolua_export105 106 void requestState(const std::string& name); //tolua_export107 void requestStates(const std::string& names); //tolua_export108 void popState(); //tolua_export109 110 const Clock& getGameClock() { return *this->gameClock_; }111 112 float getAvgTickTime() { return this->avgTickTime_; }113 float getAvgFPS() { return this->avgFPS_; }114 115 void subtractTickTime(int32_t length);116 117 template <class T>118 static bool declareGameState(const std::string& className, const std::string& stateName, bool bIgnoreTickTime, bool bConsoleMode);119 120 66 private: 121 class _CoreExport GameStateFactory122 {123 public:124 virtual ~GameStateFactory() { }125 static shared_ptr<GameState> fabricate(const GameStateInfo& info);126 template <class T>127 static void createFactory(const std::string& className)128 { getFactories()[className].reset(new TemplateGameStateFactory<T>()); }129 130 virtual shared_ptr<GameState> fabricateInternal(const GameStateInfo& info) = 0;131 static std::map<std::string, shared_ptr<GameStateFactory> >& getFactories();132 };133 template <class T>134 class TemplateGameStateFactory : public GameStateFactory135 {136 public:137 shared_ptr<GameState> fabricateInternal(const GameStateInfo& info)138 { return shared_ptr<GameState>(new T(info)); }139 };140 // For the factory destruction141 typedef Loki::ObjScopeGuardImpl0<std::map<std::string, shared_ptr<GameStateFactory> >, void (std::map<std::string, shared_ptr<GameStateFactory> >::*)()> ObjScopeGuard;142 143 struct StatisticsTickInfo144 {145 uint64_t tickTime;146 uint32_t tickLength;147 };148 149 67 Game(Game&); // don't mess with singletons 150 68 151 void loadGraphics(); 152 void unloadGraphics(); 153 154 void parseStates(std::vector<std::pair<std::string, int> >::const_iterator& it, shared_ptr<GameStateTreeNode> currentNode); 155 bool checkState(const std::string& name) const; 156 void loadState(const std::string& name); 157 void unloadState(const std::string& name); 158 159 // Main loop structuring 160 void updateGameStateStack(); 161 void updateGameStates(); 162 void updateStatistics(); 163 void updateFPSLimiter(); 164 165 // ScopeGuard helper function 166 void resetChangingState() { this->bChangingState_ = false; } 167 168 scoped_ptr<Clock> gameClock_; 169 scoped_ptr<Core> core_; 170 ObjScopeGuard gsFactoryDestroyer_; 171 172 GameStateMap constructedStates_; 173 GameStateVector loadedStates_; 174 GameStateTreeNodePtr rootStateNode_; 175 GameStateTreeNodePtr loadedTopStateNode_; 176 std::vector<GameStateTreeNodePtr> requestedStateNodes_; 177 178 bool bChangingState_; 69 QScopedPointer<Core> core_; 179 70 bool bAbort_; 180 71 181 // variables for time statistics182 uint64_t statisticsStartTime_;183 std::list<StatisticsTickInfo> statisticsTickTimes_;184 uint32_t periodTime_;185 uint32_t periodTickTime_;186 float avgFPS_;187 float avgTickTime_;188 int excessSleepTime_;189 unsigned int minimumSleepTime_;190 191 // config values192 unsigned int statisticsRefreshCycle_;193 unsigned int statisticsAvgLength_;194 unsigned int fpsLimit_;195 196 static std::map<std::string, GameStateInfo> gameStateDeclarations_s;197 72 static Game* singletonPtr_s; //!< Pointer to the Singleton 198 }; //tolua_export 199 200 template <class T> 201 /*static*/ bool Game::declareGameState(const std::string& className, const std::string& stateName, bool bIgnoreTickTime, bool bGraphicsMode) 202 { 203 std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.find(stateName); 204 if (it == gameStateDeclarations_s.end()) 205 { 206 GameStateInfo& info = gameStateDeclarations_s[stateName]; 207 info.stateName = stateName; 208 info.className = className; 209 info.bIgnoreTickTime = bIgnoreTickTime; 210 info.bGraphicsMode = bGraphicsMode; 211 } 212 else 213 { 214 COUT(0) << "Error: Cannot declare two GameStates with the same name." << std::endl; 215 COUT(0) << " Ignoring second one ('" << stateName << "')." << std::endl; 216 } 217 218 // Create a factory to delay GameState creation 219 GameStateFactory::createFactory<T>(className); 220 221 // just a required dummy return value 222 return true; 223 } 224 } //tolua_export 73 }; 74 } 225 75 226 76 #endif /* _Game_H__ */ -
sandbox_qt/src/libraries/core/PathConfig.cc
r6417 r7421 33 33 #include <cstdio> 34 34 #include <vector> 35 #include <boost/version.hpp>36 #include <boost/filesystem.hpp>37 35 38 36 #ifdef ORXONOX_PLATFORM_WINDOWS … … 54 52 #include "util/Debug.h" 55 53 #include "util/Exception.h" 56 #include "CommandLineParser.h"57 58 // Boost 1.36 has some issues with deprecated functions that have been omitted59 #if (BOOST_VERSION == 103600)60 # define BOOST_LEAF_FUNCTION filename61 #else62 # define BOOST_LEAF_FUNCTION leaf63 #endif64 54 65 55 namespace orxonox 66 56 { 67 namespace bf = boost::filesystem;68 69 57 //! Static pointer to the singleton 70 58 PathConfig* PathConfig::singletonPtr_s = 0; 71 59 72 SetCommandLineArgument(externalDataPath, "").information("Path to the external data files");73 SetCommandLineOnlyArgument(writingPathSuffix, "").information("Additional subfolder for config and log files");74 75 60 PathConfig::PathConfig() 76 : rootPath_(*(new bf::path()))77 , executablePath_(*(new bf::path()))78 , modulePath_(*(new bf::path()))79 , dataPath_(*(new bf::path()))80 , externalDataPath_(*(new bf::path()))81 , configPath_(*(new bf::path()))82 , logPath_(*(new bf::path()))83 , bDevRun_(false)84 61 { 85 62 ////////////////////////// … … 125 102 #endif 126 103 127 executablePath_ = bf::path(buffer);104 executablePath_ = QDir(buffer); 128 105 #ifndef ORXONOX_PLATFORM_APPLE 129 executablePath_ = executablePath_.branch_path(); // remove executable name 130 #endif 131 132 ///////////////////// 133 // SET MODULE PATH // 134 ///////////////////// 135 136 if (bf::exists(executablePath_ / "orxonox_dev_build.keep_me")) 106 executablePath_.cdUp(); // remove executable name 107 #endif 108 109 if (executablePath_.exists("orxonox_dev_build.keep_me")) 137 110 { 138 111 COUT(1) << "Running from the build tree." << std::endl; 139 112 PathConfig::bDevRun_ = true; 140 modulePath_ = specialConfig::moduleDevDirectory;141 113 } 142 114 else … … 146 118 147 119 // Also set the root path 148 bf::pathrelativeExecutablePath(specialConfig::defaultRuntimePath);120 QDir relativeExecutablePath(specialConfig::defaultRuntimePath); 149 121 rootPath_ = executablePath_; 150 while (!bf::equivalent(rootPath_ / relativeExecutablePath, executablePath_) && !rootPath_.empty()) 151 rootPath_ = rootPath_.branch_path(); 152 if (rootPath_.empty()) 153 ThrowException(General, "Could not derive a root directory. Might the binary installation directory contain '..' when taken relative to the installation prefix path?"); 154 155 // Module path is fixed as well 156 modulePath_ = rootPath_ / specialConfig::defaultModulePath; 122 while (rootPath_ / relativeExecutablePath != executablePath_) 123 { 124 if (!rootPath_.cdUp()) 125 ThrowException(General, "Could not derive a root directory. Might the binary installation directory contain '..' when taken relative to the installation prefix path?"); 126 } 157 127 158 128 #else 159 129 160 130 // There is no root path, so don't set it at all 161 // Module path is fixed as well162 modulePath_ = specialConfig::moduleInstallDirectory;163 131 164 132 #endif … … 168 136 PathConfig::~PathConfig() 169 137 { 170 delete &rootPath_;171 delete &executablePath_;172 delete &modulePath_;173 delete &dataPath_;174 delete &externalDataPath_;175 delete &configPath_;176 delete &logPath_;177 138 } 178 139 … … 184 145 configPath_ = specialConfig::configDevDirectory; 185 146 logPath_ = specialConfig::logDevDirectory; 186 187 // Check for data path override by the command line188 if (!CommandLineParser::getArgument("externalDataPath")->hasDefaultValue())189 externalDataPath_ = CommandLineParser::getValue("externalDataPath").getString();190 else191 externalDataPath_ = specialConfig::externalDataDevDirectory;192 147 } 193 148 else … … 213 168 if (userDataPathPtr == NULL) 214 169 ThrowException(General, "Could not retrieve user data path."); 215 bf::pathuserDataPath(userDataPathPtr);170 QDir userDataPath(userDataPathPtr); 216 171 userDataPath /= ".orxonox"; 217 172 … … 223 178 } 224 179 225 // Option to put all the config and log files in a separate folder226 if (!CommandLineParser::getArgument("writingPathSuffix")->hasDefaultValue())227 {228 const std::string& directory(CommandLineParser::getValue("writingPathSuffix").getString());229 configPath_ = configPath_ / directory;230 logPath_ = logPath_ / directory;231 }232 233 180 // Create directories to avoid problems when opening files in non existent folders. 234 std::vector<std::pair< bf::path, std::string> > directories;235 directories.push_back(std::make_pair( bf::path(configPath_), "config"));236 directories.push_back(std::make_pair( bf::path(logPath_), "log"));237 238 for (std::vector<std::pair< bf::path, std::string> >::iterator it = directories.begin();181 std::vector<std::pair<QDir, std::string> > directories; 182 directories.push_back(std::make_pair(QDir(configPath_), "config")); 183 directories.push_back(std::make_pair(QDir(logPath_), "log")); 184 185 for (std::vector<std::pair<QDir, std::string> >::iterator it = directories.begin(); 239 186 it != directories.end(); ++it) 240 187 { 241 if ( bf::exists(it->first) && !bf::is_directory(it->first))188 if (!it->first.exists()) 242 189 { 243 ThrowException(General, std::string("The ") + it->second + " directory has been preoccupied by a file! \ 244 Please remove " + it->first.string()); 245 } 246 if (bf::create_directories(it->first)) // function may not return true at all (bug?) 247 { 190 if (!it->first.mkpath(".")) 191 ThrowException(General, std::string("The ") + it->second + " directory could not be created."); 248 192 COUT(4) << "Created " << it->second << " directory" << std::endl; 249 193 } … … 251 195 } 252 196 253 std::vector<std::string> PathConfig::getModulePaths()254 {255 std::vector<std::string> modulePaths;256 257 // We search for helper files with the following extension258 const std::string& moduleextension = specialConfig::moduleExtension;259 size_t moduleextensionlength = moduleextension.size();260 261 // Add that path to the PATH variable in case a module depends on another one262 std::string pathVariable(getenv("PATH"));263 putenv(const_cast<char*>(("PATH=" + pathVariable + ';' + modulePath_.string()).c_str()));264 265 // Make sure the path exists, otherwise don't load modules266 if (!boost::filesystem::exists(modulePath_))267 return modulePaths;268 269 boost::filesystem::directory_iterator file(modulePath_);270 boost::filesystem::directory_iterator end;271 272 // Iterate through all files273 while (file != end)274 {275 const std::string& filename = file->BOOST_LEAF_FUNCTION();276 277 // Check if the file ends with the exension in question278 if (filename.size() > moduleextensionlength)279 {280 if (filename.substr(filename.size() - moduleextensionlength) == moduleextension)281 {282 // We've found a helper file283 const std::string& library = filename.substr(0, filename.size() - moduleextensionlength);284 modulePaths.push_back((modulePath_ / library).file_string());285 }286 }287 ++file;288 }289 290 return modulePaths;291 }292 293 197 /*static*/ std::string PathConfig::getRootPathString() 294 198 { 295 return getInstance().rootPath_. string() + '/';199 return getInstance().rootPath_.path().toStdString() + '/'; 296 200 } 297 201 298 202 /*static*/ std::string PathConfig::getExecutablePathString() 299 203 { 300 return getInstance().executablePath_. string() + '/';204 return getInstance().executablePath_.path().toStdString() + '/'; 301 205 } 302 206 303 207 /*static*/ std::string PathConfig::getDataPathString() 304 208 { 305 return getInstance().dataPath_.string() + '/'; 306 } 307 308 /*static*/ std::string PathConfig::getExternalDataPathString() 309 { 310 return getInstance().externalDataPath_.string() + '/'; 209 return getInstance().dataPath_.path().toStdString() + '/'; 311 210 } 312 211 313 212 /*static*/ std::string PathConfig::getConfigPathString() 314 213 { 315 return getInstance().configPath_. string() + '/';214 return getInstance().configPath_.path().toStdString() + '/'; 316 215 } 317 216 318 217 /*static*/ std::string PathConfig::getLogPathString() 319 218 { 320 return getInstance().logPath_.string() + '/'; 321 } 322 323 /*static*/ std::string PathConfig::getModulePathString() 324 { 325 return getInstance().modulePath_.string() + '/'; 219 return getInstance().logPath_.path().toStdString() + '/'; 326 220 } 327 221 } -
sandbox_qt/src/libraries/core/PathConfig.h
r7401 r7421 39 39 #include <string> 40 40 #include <vector> 41 #include <QDir> 41 42 #include "util/Singleton.h" 42 43 43 //tolua_begin44 44 namespace orxonox 45 45 { 46 //tolua_end47 46 /** 48 47 @brief 49 48 The PathConfig class is a singleton used to configure different paths. 50 49 @details 51 The class provides information about the data, config, log, executable ,52 root and modulepath.50 The class provides information about the data, config, log, executable 51 and root path. 53 52 It determines those by the use of platform specific functions. 54 53 @remarks 55 54 Not all paths are always available: 56 55 - root only when installed copyable 57 - externalData only for development builds in the build tree58 56 */ 59 class _CoreExport PathConfig //tolua_export 60 : public Singleton<PathConfig> 61 { //tolua_export 57 class _CoreExport PathConfig : public Singleton<PathConfig> 58 { 62 59 friend class Singleton<PathConfig>; 63 60 friend class Core; … … 66 63 /** 67 64 @brief 68 Retriev s the executable path and sets all hard coded fixed paths (currently only the module path)65 Retrieves the executable path and sets all hard coded fixed paths (currently only the module path) 69 66 Also checks for "orxonox_dev_build.keep_me" in the executable diretory. 70 67 If found it means that this is not an installed run, hence we … … 76 73 ~PathConfig(); 77 74 78 //! Returns the path to the root folder as boost::filesystem::path79 static const boost::filesystem::path& getRootPath()75 //! Returns the path to the root folder as QDir 76 static const QDir& getRootPath() 80 77 { return getInstance().rootPath_; } 81 //! Returns the path to the executable folder as boost::filesystem::path82 static const boost::filesystem::path& getExecutablePath()78 //! Returns the path to the executable folder as QDir 79 static const QDir& getExecutablePath() 83 80 { return getInstance().executablePath_; } 84 //! Returns the path to the data files as boost::filesystem::path85 static const boost::filesystem::path& getDataPath()81 //! Returns the path to the data files as QDir 82 static const QDir& getDataPath() 86 83 { return getInstance().dataPath_; } 87 //! Returns the path to the external data files as boost::filesystem::path 88 static const boost::filesystem::path& getExternalDataPath() 89 { return getInstance().externalDataPath_; } 90 //! Returns the path to the config files as boost::filesystem::path 91 static const boost::filesystem::path& getConfigPath() 84 //! Returns the path to the config files as QDir 85 static const QDir& getConfigPath() 92 86 { return getInstance().configPath_; } 93 //! Returns the path to the log files as boost::filesystem::path94 static const boost::filesystem::path& getLogPath()87 //! Returns the path to the log files as QDir 88 static const QDir& getLogPath() 95 89 { return getInstance().logPath_; } 96 //! Returns the path to the modules as boost::filesystem::path97 static const boost::filesystem::path& getModulePath()98 { return getInstance().modulePath_; }99 90 100 91 //! Returns the path to the root folder as std::string … … 104 95 //! Returns the path to the data files as std::string 105 96 static std::string getDataPathString(); 106 //! Returns the path to the external data files as std::string107 static std::string getExternalDataPathString();108 97 //! Returns the path to the config files as std::string 109 98 static std::string getConfigPathString(); //tolua_export 110 99 //! Returns the path to the log files as std::string 111 100 static std::string getLogPathString(); 112 //! Returns the path to the modules as std::string113 static std::string getModulePathString();114 101 115 102 //! Return trrue for runs in the build directory (not installed) … … 126 113 */ 127 114 void setConfigurablePaths(); 128 //! Returns a list with all modules declared by a *.module file in the module folder.129 std::vector<std::string> getModulePaths();130 115 131 116 //! Path to the parent directory of the ones above if program was installed with relativ paths 132 boost::filesystem::path& rootPath_; 133 boost::filesystem::path& executablePath_; //!< Path to the executable 134 boost::filesystem::path& modulePath_; //!< Path to the modules 135 boost::filesystem::path& dataPath_; //!< Path to the data files folder 136 boost::filesystem::path& externalDataPath_; //!< Path to the external data files folder 137 boost::filesystem::path& configPath_; //!< Path to the config files folder 138 boost::filesystem::path& logPath_; //!< Path to the log files folder 117 QDir rootPath_; 118 QDir executablePath_; //!< Path to the executable 119 QDir dataPath_; //!< Path to the data files folder 120 QDir configPath_; //!< Path to the config files folder 121 QDir logPath_; //!< Path to the log files folder 139 122 140 bool 123 bool bDevRun_; //!< True for runs in the build directory (not installed) 141 124 static PathConfig* singletonPtr_s; 142 125 }; //tolua_export
Note: See TracChangeset
for help on using the changeset viewer.