Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 3370 for code/trunk/src/core


Ignore:
Timestamp:
Jul 30, 2009, 2:10:44 PM (15 years ago)
Author:
rgrieder
Message:

Merged resource branch back to the trunk. Changes:

  • Automated graphics loading by evaluating whether a GameState requires it
  • Using native Tcl library (x3n)

Windows users: Update your dependency package!

Location:
code/trunk
Files:
30 edited
4 copied

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/core/CMakeLists.txt

    r3327 r3370  
    2727  GameMode.cc
    2828  GameState.cc
     29  GraphicsManager.cc
     30  GUIManager.cc
    2931  Language.cc
    3032  LuaBind.cc
     
    8082  LINK_LIBRARIES
    8183    ${OGRE_LIBRARY}
     84    ${Boost_FILESYSTEM_LIBRARY}
     85    ${Boost_SYSTEM_LIBRARY} # Filesystem dependency
    8286    ${Boost_THREAD_LIBRARY}
    83     ${Boost_FILESYSTEM_LIBRARY}
    84     ${Boost_SYSTEM_LIBRARY}
    85     ${Boost_DATE_TIME_LIBRARY} # MSVC only
     87    ${Boost_DATE_TIME_LIBRARY} # Thread dependency
     88    ${CEGUI_LIBRARY}
     89    ${CEGUILUA_LIBRARY}
    8690    ${LUA_LIBRARIES}
    8791    cpptcl_orxonox
     92    ogreceguirenderer_orxonox
    8893    ois_orxonox
    8994    tinyxml++_orxonox
  • code/trunk/src/core/Clock.h

    r3196 r3370  
    2626 *
    2727 */
    28 
    29 /**
    30     @file
    31     @brief Declaration of the Core class.
    32 
    33     The Core class is a singleton, only used to configure some variables
    34     in the core through the config-file.
    35 */
    3628
    3729#ifndef _Clock_H__
  • code/trunk/src/core/ConfigFileManager.cc

    r3301 r3370  
    4242    const char* const DEFAULT_CONFIG_FILE = "default.ini";
    4343
    44     ConfigFileManager* ConfigFileManager::singletonRef_s = 0;
     44    ConfigFileManager* ConfigFileManager::singletonPtr_s = 0;
    4545
    4646    SetConsoleCommandShortcutExtern(config).argumentCompleter(0, autocompletion::configvalueclasses()).argumentCompleter(1, autocompletion::configvalues()).argumentCompleter(2, autocompletion::configvalue());
     
    482482         : mininmalFreeType_(ConfigFileType::numberOfReservedTypes)
    483483    {
    484         assert(singletonRef_s == 0);
    485         singletonRef_s = this;
    486484    }
    487485
     
    490488        for(std::map<ConfigFileType, ConfigFile*>::const_iterator it = this->configFiles_.begin(); it != this->configFiles_.end(); )
    491489            delete (it++)->second;
    492 
    493         assert(singletonRef_s != 0);
    494         singletonRef_s = 0;
    495490    }
    496491
  • code/trunk/src/core/ConfigFileManager.h

    r3196 r3370  
    3838
    3939#include "util/OrxEnum.h"
     40#include "util/Singleton.h"
    4041
    4142namespace orxonox
     
    267268    // ConfigFileManager //
    268269    ///////////////////////
    269     class _CoreExport ConfigFileManager
    270     {
     270    class _CoreExport ConfigFileManager : public Singleton<ConfigFileManager>
     271    {
     272        friend class Singleton<ConfigFileManager>;
    271273        public:
    272274            ConfigFileManager();
     
    305307            void updateConfigValues(ConfigFileType type);
    306308
    307             static ConfigFileManager& getInstance() { assert(singletonRef_s); return *singletonRef_s; }
    308 
    309309        private:
    310310            ConfigFileManager(const ConfigFileManager&);
     
    315315            unsigned int mininmalFreeType_;
    316316
    317             static ConfigFileManager* singletonRef_s;
     317            static ConfigFileManager* singletonPtr_s;
    318318    };
    319319}
  • code/trunk/src/core/ConsoleCommandCompilation.cc

    r3198 r3370  
    9494        if (newline)
    9595        {
    96             COUT(0) << text << std::endl;
     96            COUT(0) << stripEnclosingBraces(text) << std::endl;
    9797        }
    9898        else
    9999        {
    100             COUT(0) << text;
     100            COUT(0) << stripEnclosingBraces(text);
    101101        }
    102102    }
  • code/trunk/src/core/Core.cc

    r3323 r3370  
    4141#include <cstdio>
    4242#include <boost/filesystem.hpp>
     43#include <OgreRenderWindow.h>
    4344
    4445#ifdef ORXONOX_PLATFORM_WINDOWS
     
    6869#include "CoreIncludes.h"
    6970#include "Factory.h"
     71#include "GameMode.h"
     72#include "GraphicsManager.h"
     73#include "GUIManager.h"
    7074#include "Identifier.h"
    7175#include "Language.h"
     
    7478#include "TclBind.h"
    7579#include "TclThreadManager.h"
     80#include "input/InputManager.h"
    7681
    7782namespace orxonox
    7883{
    7984    //! Static pointer to the singleton
    80     Core* Core::singletonRef_s  = 0;
     85    Core* Core::singletonPtr_s  = 0;
    8186
    8287    SetCommandLineArgument(mediaPath, "").information("Path to the media/data files");
     
    134139                .callback(this, &CoreConfiguration::debugLevelChanged);
    135140
    136             SetConfigValue(language_, Language::getLanguage().defaultLanguage_)
     141            SetConfigValue(language_, Language::getInstance().defaultLanguage_)
    137142                .description("The language of the ingame text")
    138143                .callback(this, &CoreConfiguration::languageChanged);
     
    141146                .callback(this, &CoreConfiguration::initializeRandomNumberGenerator);
    142147
    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            }
    146155        }
    147156
     
    170179        {
    171180            // Read the translation file after the language was configured
    172             Language::getLanguage().readTranslatedLanguageFile();
     181            Language::getInstance().readTranslatedLanguageFile();
    173182        }
    174183
     
    198207        void tsetMediaPath(const std::string& path)
    199208        {
    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            }
    201219        }
    202220
     
    230248
    231249    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    {
    243258        // Parse command line arguments first
    244259        CommandLine::parseCommandLine(cmdLine);
     
    256271        // create a signal handler (only active for linux)
    257272        // 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());
    259274        this->signalHandler_->doCatch(configuration_->executablePath_.string(), Core::getLogPathString() + "orxonox_crash.log");
    260275
     
    275290
    276291        // Manage ini files and set the default settings file (usually orxonox.ini)
    277         this->configFileManager_ = new ConfigFileManager();
     292        this->configFileManager_.reset(new ConfigFileManager());
    278293        this->configFileManager_->setFilename(ConfigFileType::Settings,
    279294            CommandLine::getValue("settingsFile").getString());
    280295
    281296        // Required as well for the config values
    282         this->languageInstance_ = new Language();
     297        this->languageInstance_.reset(new Language());
    283298
    284299        // Do this soon after the ConfigFileManager has been created to open up the
     
    287302
    288303        // Create the lua interface
    289         this->luaBind_ = new LuaBind();
     304        this->luaBind_.reset(new LuaBind());
    290305
    291306        // 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()));
    294309
    295310        // create a shell
    296         this->shell_ = new Shell();
     311        this->shell_.reset(new Shell());
    297312
    298313        // creates the class hierarchy for all classes with factories
     
    301316
    302317    /**
    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.
    304320    */
    305321    Core::~Core()
    306322    {
    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;
    325360    }
    326361
     
    415450    }
    416451
     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
    417461    /**
    418462    @note
     
    524568        {
    525569            COUT(1) << "Running from the build tree." << std::endl;
    526             Core::isDevBuild_ = true;
     570            Core::bDevRun_ = true;
    527571            configuration_->mediaPath_  = ORXONOX_MEDIA_DEV_PATH;
    528572            configuration_->configPath_ = ORXONOX_CONFIG_DEV_PATH;
     
    603647    }
    604648
    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;
    608699    }
    609700}
  • code/trunk/src/core/Core.h

    r3323 r3370  
    4343
    4444#include <cassert>
     45#include <boost/scoped_ptr.hpp>
    4546#include "util/OutputHandler.h"
     47#include "util/ScopeGuard.h"
     48#include "util/Singleton.h"
    4649
    4750namespace orxonox
    4851{
    4952    class CoreConfiguration;
     53    using boost::scoped_ptr;
    5054
    5155    /**
     
    5559        The class provides information about the media, config and log path.
    5660        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!
    5763    */
    58     class _CoreExport Core
     64    class _CoreExport Core : public Singleton<Core>
    5965    {
     66        typedef Loki::ScopeGuardImpl0<void (*)()> SimpleScopeGuard;
     67        friend class Singleton<Core>;
     68
    6069        public:
    6170            /**
     
    7180            void setConfigValues();
    7281
    73             void update(const Clock& time);
     82            bool preUpdate(const Clock& time) throw();
     83            bool postUpdate(const Clock& time) throw();
    7484
    75             static Core& getInstance() { assert(Core::singletonRef_s); return *Core::singletonRef_s; }
     85            void loadGraphics();
     86            void unloadGraphics();
    7687
    7788            static int   getSoftDebugLevel(OutputHandler::OutputDevice device = OutputHandler::LD_All);
     
    8798            //! Returns the path to the log files as boost::filesystem::path
    8899            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();
    89102            //! Returns the path to the data files as std::string
    90103            static std::string getMediaPathString();
     
    93106            //! Returns the path to the log files as std::string
    94107            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_; }
    95112
    96113        private:
     
    102119            void setThreadAffinity(int limitToCPU);
    103120
    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
    112136
    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_;
    115139
    116             static Core* singletonRef_s;
     140            static Core* singletonPtr_s;
    117141    };
    118142}
  • code/trunk/src/core/CorePrereqs.h

    r3327 r3370  
    123123    class FunctorMember;
    124124    class FunctorStatic;
     125    class GraphicsManager;
     126    class GUIManager;
    125127    class Identifier;
    126128    class IRC;
     
    144146    template <class T>
    145147    class ObjectListIterator;
     148    class OgreWindowEventListener;
    146149    class OrxonoxClass;
    147150    class Shell;
     
    167170    // game states
    168171    class Game;
    169     struct GameStateConstrParams;
    170172    class GameState;
     173    struct GameStateInfo;
    171174    struct GameStateTreeNode;
    172175
     
    220223}
    221224
     225// CEGUI
     226namespace 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
     238struct lua_State;
     239
    222240// TinyXML and TinyXML++
    223241class TiXmlString;
  • code/trunk/src/core/Game.cc

    r3323 r3370  
    4040#include "util/Debug.h"
    4141#include "util/Exception.h"
     42#include "util/ScopeGuard.h"
    4243#include "util/Sleep.h"
    4344#include "util/SubString.h"
     
    4849#include "CoreIncludes.h"
    4950#include "ConfigValueIncludes.h"
     51#include "GameMode.h"
    5052#include "GameState.h"
    5153
     
    5961    SetConsoleCommandShortcutExternAlias(stop_game, "exit");
    6062
    61     std::map<std::string, Game::GameStateInfo> Game::gameStateDeclarations_s;
    62     Game* Game::singletonRef_s = 0;
     63    std::map<std::string, GameStateInfo> Game::gameStateDeclarations_s;
     64    Game* Game::singletonPtr_s = 0;
    6365
    6466
     
    6971    struct GameStateTreeNode
    7072    {
    71         GameState* state_;
     73        std::string name_;
    7274        weak_ptr<GameStateTreeNode> parent_;
    7375        std::vector<shared_ptr<GameStateTreeNode> > children_;
     
    112114    Game::Game(const std::string& cmdLine)
    113115    {
    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 
    121116        this->bAbort_ = false;
    122117        bChangingState_ = false;
    123118
     119#ifdef ORXONOX_PLATFORM_WINDOWS
     120        minimumSleepTime_ = 1000/*us*/;
     121#else
     122        minimumSleepTime_ = 0/*us*/;
     123#endif
     124
    124125        // 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);
    134127
    135128        // Set up a basic clock to keep time
    136         this->gameClock_ = new Clock();
     129        this->gameClock_.reset(new Clock());
    137130
    138131        // 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
    142135        for (std::map<std::string, GameStateInfo>::const_iterator it = gameStateDeclarations_s.begin();
    143136            it != gameStateDeclarations_s.end(); ++it)
    144137        {
    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);
    149140        }
    150141
    151142        // The empty root state is ALWAYS loaded!
    152143        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_));
    156147
    157148        // Do this after the Core creation!
    158         this->configuration_ = new GameConfiguration();
     149        this->configuration_.reset(new GameConfiguration());
    159150    }
    160151
    161152    /**
    162153    @brief
     154        All destruction code is handled by scoped_ptrs and SimpleScopeGuards.
    163155    */
    164156    Game::~Game()
    165157    {
    166         // Destroy the configuration helper class instance
    167         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 everything
    175         delete this->core_;
    176         delete this->gameClock_;
    177 
    178         // Take care of the GameStateFactories
    179         GameStateFactory::destroyFactories();
    180 
    181         // Don't assign singletonRef_s with NULL! Recreation is not supported
    182158    }
    183159
     
    195171            COUT(0) << "Warning: Starting game without requesting GameState. This automatically terminates the program." << std::endl;
    196172
     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
    197182        // START GAME
    198183        // first delta time should be about 0 seconds
     
    201186        StatisticsTickInfo tickInfo = {0, 0};
    202187        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
    213191            this->gameClock_->capture();
    214192
    215             // STATISTICS
    216             StatisticsTickInfo tickInfo = {currentTime, 0};
     193            // Statistics init
     194            StatisticsTickInfo tickInfo = {gameClock_->getMicroseconds(), 0};
    217195            statisticsTickTimes_.push_back(tickInfo);
    218196            this->periodTime_ += this->gameClock_->getDeltaTimeMicroseconds();
    219197
    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            {
    266204                this->stop();
    267205                break;
    268206            }
    269207
    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            {
    276242                try
    277243                {
    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_);
    285245                }
    286246                catch (const std::exception& ex)
    287247                {
    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();
    303253                    break;
    304254                }
    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
    315314                {
    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;
    339346    }
    340347
     
    344351    }
    345352
    346     void Game::addTickTime(uint32_t length)
     353    void Game::subtractTickTime(int32_t length)
    347354    {
    348355        assert(!this->statisticsTickTimes_.empty());
    349         this->statisticsTickTimes_.back().tickLength += length;
    350         this->periodTickTime_+=length;
     356        this->statisticsTickTimes_.back().tickLength -= length;
     357        this->periodTickTime_ -= length;
    351358    }
    352359
     
    356363    void Game::requestState(const std::string& name)
    357364    {
    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;
    360368            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        }
    367376
    368377        shared_ptr<GameStateTreeNode> lastRequestedNode;
    369378        if (this->requestedStateNodes_.empty())
    370             lastRequestedNode = this->activeStateNode_;
     379            lastRequestedNode = this->loadedTopStateNode_;
    371380        else
    372381            lastRequestedNode = this->requestedStateNodes_.back();
    373         if (state == lastRequestedNode->state_)
     382        if (name == lastRequestedNode->name_)
    374383        {
    375384            COUT(2) << "Warning: Requesting the currently active state! Ignoring." << std::endl;
     
    381390        for (unsigned int i = 0; i < lastRequestedNode->children_.size(); ++i)
    382391        {
    383             if (lastRequestedNode->children_[i]->state_ == state)
     392            if (lastRequestedNode->children_[i]->name_ == name)
    384393            {
    385394                requestedNodes.push_back(lastRequestedNode->children_[i]);
     
    394403            while (currentNode != NULL)
    395404            {
    396                 if (currentNode->state_ == state)
     405                if (currentNode->name_ == name)
    397406                    break;
    398407                currentNode = currentNode->parent_.lock();
     
    418427        shared_ptr<GameStateTreeNode> lastRequestedNode;
    419428        if (this->requestedStateNodes_.empty())
    420             lastRequestedNode = this->activeStateNode_;
     429            lastRequestedNode = this->loadedTopStateNode_;
    421430        else
    422431            lastRequestedNode = this->requestedStateNodes_.back();
    423432        if (lastRequestedNode != this->rootStateNode_)
    424             this->requestState(lastRequestedNode->parent_.lock()->state_->getName());
     433            this->requestState(lastRequestedNode->parent_.lock()->name_);
    425434        else
    426435            COUT(2) << "Warning: Can't pop the internal dummy root GameState" << std::endl;
    427436    }
    428437
    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())
    433442            return it->second;
    434443        else
    435444        {
    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>();
    438451        }
    439452    }
     
    461474            std::string newStateName = it->first;
    462475            unsigned newLevel = it->second + 1; // empty root is 0
    463             GameState* newState = this->getState(newStateName);
    464             if (!newState)
     476            if (!this->checkState(newStateName))
    465477                ThrowException(GameState, "GameState with name '" << newStateName << "' not found!");
    466             if (newState == this->rootStateNode_->state_)
     478            if (newStateName == this->rootStateNode_->name_)
    467479                ThrowException(GameState, "You shouldn't use 'emptyRootGameState' in the hierarchy...");
    468480            shared_ptr<GameStateTreeNode> newNode(new GameStateTreeNode);
    469             newNode->state_ = newState;
     481            newNode->name_ = newStateName;
    470482
    471483            if (newLevel <= currentLevel)
     
    480492                newNode->parent_ = currentNode;
    481493                currentNode->children_.push_back(newNode);
    482                 currentNode->state_->addChild(newNode->state_);
    483494            }
    484495            else
     
    491502    /*** Internal ***/
    492503
    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)
    494557    {
    495558        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);
    496569        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);
    500573        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();
    501601        this->bChangingState_ = false;
    502602    }
    503603
    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);
    528609        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);
    537611    }
    538612}
  • code/trunk/src/core/Game.h

    r3323 r3370  
    4444#include <vector>
    4545#include <boost/shared_ptr.hpp>
     46#include <boost/scoped_ptr.hpp>
    4647#include <boost/preprocessor/cat.hpp>
    4748
    4849#include "util/Debug.h"
    49 #include "util/StringUtils.h"
     50#include "util/Singleton.h"
    5051
    5152/**
     
    6061{
    6162    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    };
    6274
    6375    /**
    6476    @brief
    6577        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)
    6680    */
    67     class _CoreExport Game
     81    class _CoreExport Game : public Singleton<Game>
    6882    {
     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;
    6987    public:
    7088        Game(const std::string& cmdLine);
     
    7290
    7391        void setStateHierarchy(const std::string& str);
    74         GameState* getState(const std::string& name);
     92        shared_ptr<GameState> getState(const std::string& name);
    7593
    7694        void run();
     
    86104        float getAvgFPS()      { return this->avgFPS_; }
    87105
    88         void addTickTime(uint32_t length);
     106        void subtractTickTime(int32_t length);
    89107
    90108        template <class T>
    91109        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; }
    93110
    94111    private:
     
    97114        public:
    98115            virtual ~GameStateFactory() { }
    99             static GameState* fabricate(const std::string& className, const GameStateConstrParams& params);
     116            static shared_ptr<GameState> fabricate(const GameStateInfo& info);
    100117            template <class T>
    101118            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>()); }
    104120        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;
    107123        };
    108124        template <class T>
     
    110126        {
    111127        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)); }
    122130        };
    123131
     
    130138        Game(Game&); // don't mess with singletons
    131139
    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_;
    147168
    148169        // 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_;
    155178
    156179        static std::map<std::string, GameStateInfo> gameStateDeclarations_s;
    157         static Game* singletonRef_s;        //!< Pointer to the Singleton
     180        static Game* singletonPtr_s;        //!< Pointer to the Singleton
    158181    };
    159182
     
    161184    /*static*/ bool Game::declareGameState(const std::string& className, const std::string& stateName, bool bIgnoreTickTime, bool bGraphicsMode)
    162185    {
    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);
    164187        if (it == gameStateDeclarations_s.end())
    165188        {
    166             GameStateInfo& info = gameStateDeclarations_s[getLowercase(stateName)];
     189            GameStateInfo& info = gameStateDeclarations_s[stateName];
    167190            info.stateName = stateName;
    168191            info.className = className;
  • code/trunk/src/core/GameMode.h

    r2896 r3370  
    4141    class _CoreExport GameMode
    4242    {
     43        friend class Game;
     44
    4345        public:
    4446            static bool showsGraphics() { return bShowsGraphics_s; }
     
    4749            static bool isStandalone()  { return bIsStandalone_s; }
    4850            static bool isMaster()      { return bIsMaster_s; }
    49             static void setShowsGraphics(bool val) { bShowsGraphics_s = val; updateIsMaster(); }
     51
    5052            static void setHasServer    (bool val) { bHasServer_s     = val; updateIsMaster(); }
    5153            static void setIsClient     (bool val) { bIsClient_s      = val; updateIsMaster(); }
    5254            static void setIsStandalone (bool val) { bIsStandalone_s  = val; updateIsMaster(); }
    53             static void updateIsMaster  ()         { bIsMaster_s      = (bHasServer_s || bIsStandalone_s); }
    5455
    5556        private:
     
    5758            GameMode(const GameMode& inst);
    5859            ~GameMode();
     60
     61            static void updateIsMaster()
     62            {
     63                bIsMaster_s = (bHasServer_s || bIsStandalone_s);
     64            }
    5965
    6066            static bool bShowsGraphics_s;                   //!< global variable that tells whether to show graphics
  • code/trunk/src/core/GameState.cc

    r3280 r3370  
    3838#include "util/Exception.h"
    3939#include "util/OrxAssert.h"
     40#include "Game.h"
    4041
    4142namespace orxonox
     
    4546        Constructor only initialises variables and sets the name permanently.
    4647    */
    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)
    5150    {
    5251        this->activity_.activating   = false;
     
    6766    }
    6867
    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
    7769    {
    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;
    11271    }
    11372
  • code/trunk/src/core/GameState.h

    r3280 r3370  
    4545    /**
    4646    @brief
    47         Helper class to group construction parameters for better genericity.
    48     */
    49     struct GameStateConstrParams
    50     {
    51         std::string name;
    52         bool bIgnoreTickTime;
    53     };
    54 
    55     /**
    56     @brief
    5747        An implementation of a tree to manage game states.
    5848        This leads to a certain hierarchy that is created at runtime.
     
    8777
    8878    public:
    89         GameState(const GameStateConstrParams& params);
     79        GameState(const GameStateInfo& info);
    9080        virtual ~GameState();
    9181
    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_; }
    10085
    10186    protected:
     
    10590
    10691    private:
    107         void setParent(GameState* state) { this->parent_ = state; }
    10892        void setActivity(State activity);
    10993        void activateInternal();
     
    11195        void updateInternal(const Clock& time);
    11296
    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_;
    11899    };
    119100}
  • code/trunk/src/core/IRC.cc

    r3318 r3370  
    5757        try
    5858        {
    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());
    6363        }
    6464        catch (Tcl::tcl_error const &e)
  • code/trunk/src/core/Identifier.h

    r3333 r3370  
    500500#ifdef ORXONOX_COMPILER_MSVC
    501501        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;
    503506#else
    504507        return dynamic_cast<T>(source);
  • code/trunk/src/core/Language.cc

    r3280 r3370  
    8989    // ###############################
    9090
    91     Language* Language::singletonRef_s = 0;
     91    Language* Language::singletonPtr_s = 0;
    9292
    9393    /**
     
    9696    Language::Language()
    9797    {
    98         assert(singletonRef_s == 0);
    99         singletonRef_s = this;
    100 
    10198        this->defaultLanguage_ = "default";
    10299        this->defaultLocalisation_ = "ERROR: LANGUAGE ENTRY DOESN'T EXIST!";
     
    113110        for (std::map<std::string, LanguageEntry*>::iterator it = this->languageEntries_.begin(); it != this->languageEntries_.end(); ++it)
    114111            delete (it->second);
    115 
    116         assert(singletonRef_s);
    117         singletonRef_s = 0;
    118112    }
    119113
  • code/trunk/src/core/Language.h

    r3280 r3370  
    3737    Usage:
    3838     - Set the entry with the default string:
    39        Language::getLanguage()->addEntry("label of the entry", "the string to translate");
     39       Language::getInstance()->addEntry("label of the entry", "the string to translate");
    4040
    4141     - Get the localisation of the entry in the configured language:
    42        std::cout << Language::getLanguage()->getLocalisation("name of the entry") << std::endl;
     42       std::cout << Language::getInstance()->getLocalisation("name of the entry") << std::endl;
    4343*/
    4444
     
    5151#include <string>
    5252#include <cassert>
     53#include "util/Singleton.h"
    5354
    5455#define AddLanguageEntry(label, fallbackstring) \
    55     orxonox::Language::getLanguage().addEntry(label, fallbackstring)
     56    orxonox::Language::getInstance().addEntry(label, fallbackstring)
    5657
    5758#define GetLocalisation(label) \
    58     orxonox::Language::getLanguage().getLocalisation(label)
     59    orxonox::Language::getInstance().getLocalisation(label)
    5960
    6061
     
    112113    // ###############################
    113114    //! 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>
    115116    {
     117        friend class Singleton<Language>;
    116118        friend class CoreConfiguration;
    117119
     
    120122            ~Language();
    121123
    122             static Language& getLanguage() { assert(singletonRef_s); return *singletonRef_s; }
    123124            void addEntry(const LanguageEntryLabel& label, const std::string& entry);
    124125            const std::string& getLocalisation(const LanguageEntryLabel& label) const;
     
    137138            std::map<std::string, LanguageEntry*> languageEntries_; //!< A map to store all LanguageEntry objects and their labels
    138139
    139             static Language* singletonRef_s;
     140            static Language* singletonPtr_s;
    140141    };
    141142}
  • code/trunk/src/core/Loader.cc

    r3196 r3370  
    3030
    3131#include <tinyxml/ticpp.h>
    32 #include <boost/filesystem.hpp>
    3332
    3433#include "util/Debug.h"
    3534#include "util/Exception.h"
    3635#include "BaseObject.h"
    37 #include "Core.h"
    3836#include "Iterator.h"
    3937#include "ObjectList.h"
     
    210208        return Loader::load(file, mask);
    211209    }
    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     }
    232210}
  • code/trunk/src/core/Loader.h

    r3196 r3370  
    5656
    5757            static ClassTreeMask currentMask_s;
    58             static std::vector<std::string> getLevelList();
    5958
    6059        private:
  • code/trunk/src/core/LuaBind.cc

    r3301 r3370  
    3939#include "util/Debug.h"
    4040#include "util/StringUtils.h"
    41 #include "ToluaBindCore.h"
    4241#include "Core.h"
    4342
    4443namespace orxonox
    4544{
    46   LuaBind* LuaBind::singletonRef_s = NULL;
     45  LuaBind* LuaBind::singletonPtr_s = NULL;
    4746
    4847  LuaBind::LuaBind()
    4948  {
    50     assert(LuaBind::singletonRef_s == 0);
    51     LuaBind::singletonRef_s = this;
    52 
    5349    this->includePath_ = Core::getMediaPathString();
    5450
     
    6561    luaopen_debug(luaState_);
    6662#endif
    67     tolua_Core_open(luaState_);
     63
     64    // Open all available tolua interfaces
     65    this->openToluaInterfaces(luaState_);
     66
    6867    output_ = "";
    6968    isRunning_ = false;
    7069  }
     70
     71  LuaBind::~LuaBind()
     72  {
     73    this->closeToluaInterfaces(luaState_);
     74  };
    7175
    7276  void LuaBind::luaPrint(const std::string& str)
     
    315319  }
    316320
     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
    317343}
  • code/trunk/src/core/LuaBind.h

    r3196 r3370  
    4040#include <cassert>
    4141#include <string>
     42#include <vector>
    4243extern "C" {
    4344#include <lua.h>
    4445}
    4546
     47#include "util/Singleton.h"
     48
    4649// tolua_begin
    4750namespace orxonox
    4851{
    49   class _CoreExport LuaBind
     52  class _CoreExport LuaBind : public Singleton<LuaBind>
    5053  {
     54// tolua_end
     55    friend class Singleton<LuaBind>;
    5156
    52 // tolua_end
    5357    struct LoadS {
    5458      const char *s;
     
    5862    public:
    5963      LuaBind();
    60       inline ~LuaBind() { assert(singletonRef_s); LuaBind::singletonRef_s = NULL; };
     64      ~LuaBind();
    6165
    62       inline static LuaBind& getInstance() { assert(singletonRef_s); return *LuaBind::singletonRef_s; } // tolua_export
     66      static LuaBind& getInstance() { return Singleton<LuaBind>::getInstance(); } // tolua_export
    6367
    6468    void loadFile(const std::string& filename, bool luaTags);
     
    8387        { this->includePath_ = includepath; }
    8488
     89    void addToluaInterface(int (*function)(lua_State*), const std::string& name);
     90    void openToluaInterfaces(lua_State* state);
     91    void closeToluaInterfaces(lua_State* state);
     92
    8593    private:
    86       static LuaBind* singletonRef_s;
     94      static LuaBind* singletonPtr_s;
    8795
    8896      std::string luaSource_;
     
    9199      bool isRunning_;
    92100      std::string includePath_;
     101      std::vector<std::pair<std::string, int (*)(lua_State *L)> > toluaInterfaces_;
    93102
    94103  }; // tolua_export
  • code/trunk/src/core/Shell.cc

    r3301 r3370  
    5151    SetConsoleCommandShortcut(OutputHandler, debug);
    5252
    53     Shell* Shell::singletonRef_s = 0;
     53    Shell* Shell::singletonPtr_s = 0;
    5454
    5555    Shell::Shell()
    5656    {
    57         assert(singletonRef_s == 0);
    58         singletonRef_s = this;
    59 
    6057        int level = Core::getSoftDebugLevel(OutputHandler::LD_Shell);
    6158        Core::setSoftDebugLevel(OutputHandler::LD_Shell, -1);
     
    9289        if (this->inputBuffer_)
    9390            delete this->inputBuffer_;
    94         singletonRef_s = 0;
    9591    }
    9692
  • code/trunk/src/core/Shell.h

    r3280 r3370  
    6060    };
    6161
    62     class _CoreExport Shell : virtual public OrxonoxClass, public OutputBufferListener
     62    class _CoreExport Shell : public Singleton<Shell>, virtual public OrxonoxClass, public OutputBufferListener
    6363    {
     64        friend class Singleton<Shell>;
    6465        public:
    6566            Shell();
    6667            virtual ~Shell();
    67 
    68             static Shell& getInstance() { assert(singletonRef_s); return *singletonRef_s; }
    6968
    7069            static void clearShell();
     
    148147            ConfigFileType commandHistoryConfigFileType_;
    149148
    150             static Shell* singletonRef_s;
     149            static Shell* singletonPtr_s;
    151150    };
    152151}
  • code/trunk/src/core/TclBind.cc

    r3318 r3370  
    3333#include <cpptcl/cpptcl.h>
    3434
     35#include "SpecialConfig.h"
    3536#include "util/Debug.h"
    3637#include "util/StringUtils.h"
    3738#include "CommandExecutor.h"
    3839#include "ConsoleCommand.h"
     40#include "Core.h"
    3941#include "TclThreadManager.h"
    4042
     
    4446    SetConsoleCommandShortcut(TclBind, bgerror);
    4547
    46     TclBind* TclBind::singletonRef_s = 0;
     48    TclBind* TclBind::singletonPtr_s = 0;
    4749
    4850    TclBind::TclBind(const std::string& datapath)
    4951    {
    50         assert(singletonRef_s == 0);
    51         singletonRef_s = this;
    5252        this->interpreter_ = 0;
    53         this->bSetTclLibPath_ = false;
     53        this->bSetTclDataPath_ = false;
    5454        this->setDataPath(datapath);
    5555    }
     
    5959        if (this->interpreter_)
    6060            delete this->interpreter_;
    61         singletonRef_s = 0;
    6261    }
    6362
     
    6564    {
    6665        // 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());
    8080            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());
    8282
    8383            try
    8484            {
    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 }");
    8889                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 }");
    9191            }
    9292            catch (Tcl::tcl_error const &e)
     
    9494            catch (std::exception const &e)
    9595            {   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
    108135    }
    109136
     
    142169            try
    143170            {
    144                 std::string output = TclBind::getInstance().interpreter_->eval(tclcode);
     171                std::string output = TclBind::getInstance().interpreter_->eval("uplevel #0 " + tclcode);
    145172                if (output != "")
    146173                {
  • code/trunk/src/core/TclBind.h

    r3196 r3370  
    3434#include <cassert>
    3535#include <string>
     36#include "util/Singleton.h"
    3637
    3738namespace orxonox
    3839{
    39     class _CoreExport TclBind
     40    class _CoreExport TclBind : public Singleton<TclBind>
    4041    {
     42        friend class Singleton<TclBind>;
    4143        public:
    4244            TclBind(const std::string& datapath);
    4345            ~TclBind();
    44 
    45             static TclBind& getInstance() { assert(singletonRef_s); return *singletonRef_s; }
    4646
    4747            static std::string tcl(const std::string& tclcode);
     
    4949
    5050            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();
    5456            Tcl::interpreter* getTclInterpreter() const { return this->interpreter_; }
    5557
     
    6365
    6466            Tcl::interpreter* interpreter_;
    65             std::string tclLibPath_;
    66             bool bSetTclLibPath_;
     67            std::string tclDataPath_;
     68            bool bSetTclDataPath_;
    6769
    68             static TclBind* singletonRef_s;
     70            static TclBind* singletonPtr_s;
    6971    };
    7072}
  • code/trunk/src/core/TclThreadManager.cc

    r3326 r3370  
    5454    SetConsoleCommand(TclThreadManager, execute, false).argumentCompleter(0, autocompletion::tclthreads());
    5555    SetConsoleCommand(TclThreadManager, query,   false).argumentCompleter(0, autocompletion::tclthreads());
     56    SetConsoleCommand(TclThreadManager, source,  false).argumentCompleter(0, autocompletion::tclthreads());
    5657
    5758    /**
     
    9091        RegisterRootObject(TclThreadManager);
    9192
    92         assert(TclThreadManager::singletonPtr_s == 0);
    93         TclThreadManager::singletonPtr_s = this;
    94 
    9593        this->numInterpreterBundles_ = 0;
    9694
     
    115113    TclThreadManager::~TclThreadManager()
    116114    {
    117         TclThreadManager::singletonPtr_s = 0;
    118 
    119115        delete this->interpreterBundlesMutex_;
    120116//        delete this->mainInterpreterMutex_; // <-- temporary disabled to avoid crash if a thread is still actively queriyng
     
    240236        TclInterpreterBundle* newbundle = new TclInterpreterBundle();
    241237        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);
    283241
    284242        {
     
    291249    }
    292250
     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
    293293    /**
    294294        @brief Stops and destroys a given Tcl-interpreter
     
    298298        // TODO
    299299        // Not yet implemented
     300        TclInterpreterBundle* bundle = TclThreadManager::getInstance().getInterpreterBundle(id);
     301        if (bundle)
     302        {
     303            bundle->bRunning_ = false;
     304        }
    300305    }
    301306
     
    399404            {
    400405                // 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_) \
    402407                            + " -> " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
    403408                            + "), couldn't query Tcl-interpreter with ID " + getConvertedValue<unsigned int, std::string>(target_bundle->id_) \
     
    435440                    {
    436441                        // It's a query to the CommandExecutor
    437                         this->debug("TclThread_query -> CE: " + command);
     442                        TclThreadManager::debug("TclThread_query -> CE: " + command);
    438443                        if (!CommandExecutor::execute(command, false))
    439                             this->error("Error: Can't execute command \"" + command + "\"!");
     444                            TclThreadManager::error("Error: Can't execute command \"" + command + "\"!");
    440445
    441446                        if (CommandExecutor::getLastEvaluation().hasReturnvalue())
     
    445450                    {
    446451                        // 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");
    450455                    }
    451456
     
    464469                    // This happens if the main thread tries to query a busy interpreter
    465470                    // 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.");
    467472                }
    468473            }
     
    471476
    472477        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));
    473486    }
    474487
     
    502515        else
    503516        {
    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.");
    505518            return 0;
    506519        }
     
    544557    void TclThreadManager::error(const std::string& error)
    545558    {
    546         this->messageQueue_->push_back("error " + error);
     559        TclThreadManager::getInstance().messageQueue_->push_back("error " + error);
    547560    }
    548561
     
    552565    void TclThreadManager::debug(const std::string& error)
    553566    {
    554         this->messageQueue_->push_back("debug " + error);
     567        TclThreadManager::getInstance().messageQueue_->push_back("debug " + error);
    555568    }
    556569
     
    561574        Errors are reported through the @ref error function.
    562575    */
    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)
    564577    {
    565578        Tcl_Interp* interpreter = bundle->interpreter_->get();
     
    570583        if (cc != TCL_OK)
    571584        {
    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));
    573586            return "";
    574587        }
     
    590603    void tclThread(TclInterpreterBundle* bundle, std::string command)
    591604    {
    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");
    595608
    596609        bundle->lock_->unlock();
    597610    }
     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    }
    598672}
  • code/trunk/src/core/TclThreadManager.h

    r3321 r3370  
    3333
    3434#include <cassert>
     35#include <list>
    3536#include <map>
    3637#include <string>
    3738
     39#include "util/Singleton.h"
    3840#include "OrxonoxClass.h"
     41
     42struct Tcl_Interp;
    3943
    4044namespace orxonox
    4145{
    42     class _CoreExport TclThreadManager : public OrxonoxClass
     46    class _CoreExport TclThreadManager : public Singleton<TclThreadManager>, public OrxonoxClass
    4347    {
     48        friend class Singleton<TclThreadManager>;
    4449        friend class TclBind;
    4550        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);
    4653
    4754        public:
    4855            TclThreadManager(Tcl::interpreter* interpreter);
    4956            virtual ~TclThreadManager();
    50 
    51             static TclThreadManager& getInstance() { assert(TclThreadManager::singletonPtr_s); return *TclThreadManager::singletonPtr_s; }
    5257
    5358            static unsigned int      create();
     
    5661            static void              execute(unsigned int target_id, const std::string& command);
    5762            static std::string       query(unsigned int target_id, const std::string& command);
     63            static void              source(const std::string& file);
    5864
    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);
    6167
    6268            void update(const Clock& time);
     
    7783            std::string dumpList(const std::list<unsigned int>& list);
    7884
    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);
    8087
    8188            static TclThreadManager* singletonPtr_s;                            ///< Singleton pointer
     
    8996
    9097    _CoreExport void tclThread(TclInterpreterBundle* bundle, std::string command);
     98    _CoreExport void sourceThread(std::string file);
     99    _CoreExport int Tcl_OrxonoxAppInit(Tcl_Interp* interp);
    91100}
    92101
  • code/trunk/src/core/input/InputManager.cc

    r3331 r3370  
    6464    InputHandler InputHandler::EMPTY;
    6565
    66     InputManager* InputManager::singletonRef_s = 0;
     66    InputManager* InputManager::singletonPtr_s = 0;
    6767
    6868    //! Defines the |= operator for easier use.
     
    9393        RegisterRootObject(InputManager);
    9494
    95         assert(singletonRef_s == 0);
    96         singletonRef_s = this;
    97 
    9895        CCOUT(4) << "Constructing..." << std::endl;
    9996
     
    138135        }
    139136
     137        CCOUT(4) << "Construction complete." << std::endl;
    140138        internalState_ = Nothing;
    141         CCOUT(4) << "Construction complete." << std::endl;
    142139    }
    143140
     
    297294
    298295        CCOUT(4) << "Destruction complete." << std::endl;
    299         singletonRef_s = 0;
    300296    }
    301297
  • code/trunk/src/core/input/InputManager.h

    r3327 r3370  
    3737#include <vector>
    3838
     39#include "util/Singleton.h"
    3940#include "core/WindowEventListener.h"
    4041#include "InputState.h"
     
    6263          If the OIS::InputManager or the Keyboard fail, an exception is thrown.
    6364    */
    64     class _CoreExport InputManager : public WindowEventListener
     65    class _CoreExport InputManager : public Singleton<InputManager>, public WindowEventListener
    6566    {
     67        friend class Singleton<InputManager>;
    6668    public:
    6769        //! Represents internal states of the InputManager.
     
    168170            { return this->oisInputManager_; }
    169171
    170         //! Returns a reference to the singleton instance
    171         static InputManager& getInstance() { assert(singletonRef_s); return *singletonRef_s; }
    172 
    173172    private: // functions
    174173        // don't mess with a Singleton
     
    211210        std::set<InputState*>               stateDestroyRequests_; //!< Requests to destroy a state
    212211
    213         static InputManager*                singletonRef_s;        //!< Pointer reference to the singleton
     212        static InputManager*                singletonPtr_s;        //!< Pointer reference to the singleton
    214213    };
    215214}
Note: See TracChangeset for help on using the changeset viewer.