Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/libraries/src/core/Core.cc @ 5649

Last change on this file since 5649 was 5649, checked in by rgrieder, 15 years ago

Fixed msvc build: I had to link the plugins as SHARED instead of MODULE because CMake doesn't allow modules to be linked against another module.
The reason why it did work after all was because the quest library was built before overlays causing CMake to link against whatever it found under the name "overlays" in the end (which was of course the output file instead of the CMake representation of a library). Since msvc never links against dlls but rather against the corresponding *.lib file things got completely busted.

Also added the proposed fix for the PATH variable (successfully tested under Windows by deleting the overlays.plugin file).

  • Property svn:eol-style set to native
File size: 28.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Reto Grieder
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30/**
31@file
32@brief
33    Implementation of the Core singleton with its global variables (avoids boost include)
34*/
35
36#include "Core.h"
37
38#include <cassert>
39#include <fstream>
40#include <cstdlib>
41#include <cstdio>
42#include <boost/version.hpp>
43#include <boost/filesystem.hpp>
44#include <OgreRenderWindow.h>
45
46#ifdef ORXONOX_PLATFORM_WINDOWS
47#  ifndef WIN32_LEAN_AND_MEAN
48#    define WIN32_LEAN_AND_MEAN
49#  endif
50#  include <windows.h>
51#  undef min
52#  undef max
53#elif defined(ORXONOX_PLATFORM_APPLE)
54#  include <sys/param.h>
55#  include <mach-o/dyld.h>
56#else /* Linux */
57#  include <sys/types.h>
58#  include <unistd.h>
59#endif
60
61#include "SpecialConfig.h"
62#include "util/Debug.h"
63#include "util/Exception.h"
64#include "util/SignalHandler.h"
65#include "Clock.h"
66#include "CommandExecutor.h"
67#include "CommandLine.h"
68#include "ConfigFileManager.h"
69#include "ConfigValueIncludes.h"
70#include "CoreIncludes.h"
71#include "DynLibManager.h"
72#include "Factory.h"
73#include "GameMode.h"
74#include "GraphicsManager.h"
75#include "GUIManager.h"
76#include "Identifier.h"
77#include "Language.h"
78#include "LuaBind.h"
79#include "Shell.h"
80#include "TclBind.h"
81#include "TclThreadManager.h"
82#include "input/InputManager.h"
83
84// Boost 1.36 has some issues with deprecated functions that have been omitted
85#if (BOOST_VERSION == 103600)
86#  define BOOST_LEAF_FUNCTION filename
87#else
88#  define BOOST_LEAF_FUNCTION leaf
89#endif
90
91namespace orxonox
92{
93    //! Static pointer to the singleton
94    Core* Core::singletonPtr_s  = 0;
95
96    SetCommandLineArgument(mediaPath, "").information("Path to the media/data files");
97    SetCommandLineOnlyArgument(writingPathSuffix, "").information("Additional subfolder for config and log files");
98    SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
99#ifdef ORXONOX_PLATFORM_WINDOWS
100    SetCommandLineArgument(limitToCPU, 0).information("Limits the program to one cpu/core (1, 2, 3, etc.). 0 turns it off (default)");
101#endif
102
103    /**
104    @brief
105        Helper class for the Core singleton: we cannot derive
106        Core from OrxonoxClass because we need to handle the Identifier
107        destruction in the Core destructor.
108    */
109    class CoreConfiguration : public OrxonoxClass
110    {
111    public:
112        CoreConfiguration()
113        {
114        }
115
116        void initialise()
117        {
118            RegisterRootObject(CoreConfiguration);
119            this->setConfigValues();
120
121            // Possible media path override by the command line
122            if (!CommandLine::getArgument("mediaPath")->hasDefaultValue())
123                tsetMediaPath(CommandLine::getValue("mediaPath"));
124        }
125
126        /**
127            @brief Function to collect the SetConfigValue-macro calls.
128        */
129        void setConfigValues()
130        {
131#ifdef NDEBUG
132            const unsigned int defaultLevelConsole = 1;
133            const unsigned int defaultLevelLogfile = 3;
134            const unsigned int defaultLevelShell   = 1;
135#else
136            const unsigned int defaultLevelConsole = 3;
137            const unsigned int defaultLevelLogfile = 4;
138            const unsigned int defaultLevelShell   = 3;
139#endif
140            SetConfigValue(softDebugLevelConsole_, defaultLevelConsole)
141                .description("The maximal level of debug output shown in the console")
142                .callback(this, &CoreConfiguration::debugLevelChanged);
143            SetConfigValue(softDebugLevelLogfile_, defaultLevelLogfile)
144                .description("The maximal level of debug output shown in the logfile")
145                .callback(this, &CoreConfiguration::debugLevelChanged);
146            SetConfigValue(softDebugLevelShell_, defaultLevelShell)
147                .description("The maximal level of debug output shown in the ingame shell")
148                .callback(this, &CoreConfiguration::debugLevelChanged);
149
150            SetConfigValue(language_, Language::getInstance().defaultLanguage_)
151                .description("The language of the ingame text")
152                .callback(this, &CoreConfiguration::languageChanged);
153            SetConfigValue(bInitializeRandomNumberGenerator_, true)
154                .description("If true, all random actions are different each time you start the game")
155                .callback(this, &CoreConfiguration::initializeRandomNumberGenerator);
156
157            // Only show this config value for development builds
158            if (Core::isDevelopmentRun())
159            {
160                SetConfigValue(mediaPathString_, mediaPath_.string())
161                    .description("Relative path to the game data.")
162                    .callback(this, &CoreConfiguration::mediaPathChanged);
163            }
164        }
165
166        /**
167            @brief Callback function if the debug level has changed.
168        */
169        void debugLevelChanged()
170        {
171            // softDebugLevel_ is the maximum of the 3 variables
172            this->softDebugLevel_ = this->softDebugLevelConsole_;
173            if (this->softDebugLevelLogfile_ > this->softDebugLevel_)
174                this->softDebugLevel_ = this->softDebugLevelLogfile_;
175            if (this->softDebugLevelShell_ > this->softDebugLevel_)
176                this->softDebugLevel_ = this->softDebugLevelShell_;
177
178            OutputHandler::setSoftDebugLevel(OutputHandler::LD_All,     this->softDebugLevel_);
179            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Console, this->softDebugLevelConsole_);
180            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Logfile, this->softDebugLevelLogfile_);
181            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Shell,   this->softDebugLevelShell_);
182        }
183
184        /**
185            @brief Callback function if the language has changed.
186        */
187        void languageChanged()
188        {
189            // Read the translation file after the language was configured
190            Language::getInstance().readTranslatedLanguageFile();
191        }
192
193        /**
194        @brief
195            Callback function if the media path has changed.
196        */
197        void mediaPathChanged()
198        {
199            mediaPath_ = boost::filesystem::path(this->mediaPathString_);
200        }
201
202        /**
203            @brief Sets the language in the config-file back to the default.
204        */
205        void resetLanguage()
206        {
207            ResetConfigValue(language_);
208        }
209
210        /**
211        @brief
212            Temporary sets the media path
213        @param path
214            The new media path
215        */
216        void tsetMediaPath(const std::string& path)
217        {
218            if (Core::isDevelopmentRun())
219            {
220                ModifyConfigValue(mediaPathString_, tset, path);
221            }
222            else
223            {
224                // Manual 'config' value without the file entry
225                mediaPathString_ = path;
226                this->mediaPathChanged();
227            }
228        }
229
230        void initializeRandomNumberGenerator()
231        {
232            static bool bInitialized = false;
233            if (!bInitialized && this->bInitializeRandomNumberGenerator_)
234            {
235                srand(static_cast<unsigned int>(time(0)));
236                rand();
237                bInitialized = true;
238            }
239        }
240
241        int softDebugLevel_;                            //!< The debug level
242        int softDebugLevelConsole_;                     //!< The debug level for the console
243        int softDebugLevelLogfile_;                     //!< The debug level for the logfile
244        int softDebugLevelShell_;                       //!< The debug level for the ingame shell
245        std::string language_;                          //!< The language
246        bool bInitializeRandomNumberGenerator_;         //!< If true, srand(time(0)) is called
247        std::string mediaPathString_;                   //!< Path to the data/media file folder as string
248
249        //! Path to the parent directory of the ones above if program was installed with relativ pahts
250        boost::filesystem::path rootPath_;
251        boost::filesystem::path executablePath_;        //!< Path to the executable
252        boost::filesystem::path pluginPath_;            //!< Path to the plugins
253        boost::filesystem::path mediaPath_;             //!< Path to the media file folder
254        boost::filesystem::path configPath_;            //!< Path to the config file folder
255        boost::filesystem::path logPath_;               //!< Path to the log file folder
256    };
257
258
259    Core::Core(const std::string& cmdLine)
260        // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)
261        : identifierDestroyer_(Identifier::destroyAllIdentifiers)
262        // Cleanup guard for external console commands that don't belong to an Identifier
263        , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands)
264        , configuration_(new CoreConfiguration()) // Don't yet create config values!
265        , bDevRun_(false)
266        , bGraphicsLoaded_(false)
267    {
268        // Set the hard coded fixed paths
269        this->setFixedPaths();
270
271        // Create a new dynamic library manager
272        this->dynLibManager_.reset(new DynLibManager());
273
274        // Load plugins
275        try
276        {
277            // We search for helper files with the following extension
278            std::string pluginextension = ".plugin";
279            size_t pluginextensionlength = pluginextension.size();
280
281            // Search in the directory of our executable
282            boost::filesystem::path searchpath = this->configuration_->pluginPath_;
283
284            // Add that path to the PATH variable in case a plugin depends on another one
285            std::string pathVariable = getenv("PATH");
286            putenv(("PATH=" + pathVariable + ";" + configuration_->pluginPath_.string()).c_str());
287
288            boost::filesystem::directory_iterator file(searchpath);
289            boost::filesystem::directory_iterator end;
290
291            // Iterate through all files
292            while (file != end)
293            {
294                std::string filename = file->BOOST_LEAF_FUNCTION();
295
296                // Check if the file ends with the exension in question
297                if (filename.size() > pluginextensionlength)
298                {
299                    if (filename.substr(filename.size() - pluginextensionlength) == pluginextension)
300                    {
301                        // We've found a helper file - now load the library with the same name
302                        std::string library = filename.substr(0, filename.size() - pluginextensionlength);
303                        boost::filesystem::path librarypath = searchpath / library;
304
305                        try
306                        {
307                            DynLibManager::getInstance().load(librarypath.string());
308                        }
309                        catch (const std::exception& e)
310                        {
311                            COUT(1) << "Couldn't load plugin \"" << librarypath.string() << "\": " << e.what() << std::endl;
312                        }
313                        catch (...)
314                        {
315                            COUT(1) << "Couldn't load plugin \"" << librarypath.string() << "\"" << std::endl;
316                        }
317                    }
318                }
319
320                ++file;
321            }
322        }
323        catch (const std::exception& e)
324        {
325            COUT(1) << "An error occurred while loading plugins: " << e.what() << std::endl;
326        }
327        catch (...)
328        {
329            COUT(1) << "An error occurred while loading plugins." << std::endl;
330        }
331
332        // Parse command line arguments AFTER the plugins have been loaded (static code!)
333        CommandLine::parseCommandLine(cmdLine);
334
335        // Set configurable paths like log, config and media
336        this->setConfigurablePaths();
337
338        // create a signal handler (only active for linux)
339        // This call is placed as soon as possible, but after the directories are set
340        this->signalHandler_.reset(new SignalHandler());
341        this->signalHandler_->doCatch(configuration_->executablePath_.string(), Core::getLogPathString() + "orxonox_crash.log");
342
343        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% was used
344        OutputHandler::getOutStream().setLogPath(Core::getLogPathString());
345
346        // Parse additional options file now that we know its path
347        CommandLine::parseFile();
348
349#ifdef ORXONOX_PLATFORM_WINDOWS
350        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
351        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
352        // the timer though).
353        int limitToCPU = CommandLine::getValue("limitToCPU");
354        if (limitToCPU > 0)
355            setThreadAffinity(static_cast<unsigned int>(limitToCPU));
356#endif
357
358        // Manage ini files and set the default settings file (usually orxonox.ini)
359        this->configFileManager_.reset(new ConfigFileManager());
360        this->configFileManager_->setFilename(ConfigFileType::Settings,
361            CommandLine::getValue("settingsFile").getString());
362
363        // Required as well for the config values
364        this->languageInstance_.reset(new Language());
365
366        // Do this soon after the ConfigFileManager has been created to open up the
367        // possibility to configure everything below here
368        this->configuration_->initialise();
369
370        // Create the lua interface
371        this->luaBind_.reset(new LuaBind());
372
373        // initialise Tcl
374        this->tclBind_.reset(new TclBind(Core::getMediaPathString()));
375        this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
376
377        // create a shell
378        this->shell_.reset(new Shell());
379
380        // creates the class hierarchy for all classes with factories
381        Factory::createClassHierarchy();
382    }
383
384    /**
385    @brief
386        All destruction code is handled by scoped_ptrs and SimpleScopeGuards.
387    */
388    Core::~Core()
389    {
390    }
391
392    void Core::loadGraphics()
393    {
394        if (bGraphicsLoaded_)
395            return;
396
397        // Load OGRE including the render window
398        scoped_ptr<GraphicsManager> graphicsManager(new GraphicsManager());
399
400        // The render window width and height are used to set up the mouse movement.
401        size_t windowHnd = 0;
402        graphicsManager->getRenderWindow()->getCustomAttribute("WINDOW", &windowHnd);
403
404        // Calls the InputManager which sets up the input devices.
405        scoped_ptr<InputManager> inputManager(new InputManager(windowHnd));
406
407        // load the CEGUI interface
408        guiManager_.reset(new GUIManager(graphicsManager->getRenderWindow()));
409
410        // Dismiss scoped pointers
411        graphicsManager_.swap(graphicsManager);
412        inputManager_.swap(inputManager);
413
414        bGraphicsLoaded_ = true;
415    }
416
417    void Core::unloadGraphics()
418    {
419        if (!bGraphicsLoaded_)
420            return;
421
422        this->guiManager_.reset();;
423        this->inputManager_.reset();;
424        this->graphicsManager_.reset();
425
426        bGraphicsLoaded_ = false;
427    }
428
429    /**
430        @brief Returns the softDebugLevel for the given device (returns a default-value if the class is right about to be created).
431        @param device The device
432        @return The softDebugLevel
433    */
434    /*static*/ int Core::getSoftDebugLevel(OutputHandler::OutputDevice device)
435    {
436        switch (device)
437        {
438        case OutputHandler::LD_All:
439            return Core::getInstance().configuration_->softDebugLevel_;
440        case OutputHandler::LD_Console:
441            return Core::getInstance().configuration_->softDebugLevelConsole_;
442        case OutputHandler::LD_Logfile:
443            return Core::getInstance().configuration_->softDebugLevelLogfile_;
444        case OutputHandler::LD_Shell:
445            return Core::getInstance().configuration_->softDebugLevelShell_;
446        default:
447            assert(0);
448            return 2;
449        }
450    }
451
452     /**
453        @brief Sets the softDebugLevel for the given device. Please use this only temporary and restore the value afterwards, as it overrides the configured value.
454        @param device The device
455        @param level The level
456    */
457    /*static*/ void Core::setSoftDebugLevel(OutputHandler::OutputDevice device, int level)
458    {
459        if (device == OutputHandler::LD_All)
460            Core::getInstance().configuration_->softDebugLevel_ = level;
461        else if (device == OutputHandler::LD_Console)
462            Core::getInstance().configuration_->softDebugLevelConsole_ = level;
463        else if (device == OutputHandler::LD_Logfile)
464            Core::getInstance().configuration_->softDebugLevelLogfile_ = level;
465        else if (device == OutputHandler::LD_Shell)
466            Core::getInstance().configuration_->softDebugLevelShell_ = level;
467
468        OutputHandler::setSoftDebugLevel(device, level);
469    }
470
471    /**
472        @brief Returns the configured language.
473    */
474    /*static*/ const std::string& Core::getLanguage()
475    {
476        return Core::getInstance().configuration_->language_;
477    }
478
479    /**
480        @brief Sets the language in the config-file back to the default.
481    */
482    /*static*/ void Core::resetLanguage()
483    {
484        Core::getInstance().configuration_->resetLanguage();
485    }
486
487    /*static*/ void Core::tsetMediaPath(const std::string& path)
488    {
489        getInstance().configuration_->tsetMediaPath(path);
490    }
491
492    /*static*/ const boost::filesystem::path& Core::getMediaPath()
493    {
494        return getInstance().configuration_->mediaPath_;
495    }
496    /*static*/ std::string Core::getMediaPathString()
497    {
498        return getInstance().configuration_->mediaPath_.string() + '/';
499    }
500
501    /*static*/ const boost::filesystem::path& Core::getConfigPath()
502    {
503        return getInstance().configuration_->configPath_;
504    }
505    /*static*/ std::string Core::getConfigPathString()
506    {
507        return getInstance().configuration_->configPath_.string() + '/';
508    }
509
510    /*static*/ const boost::filesystem::path& Core::getLogPath()
511    {
512        return getInstance().configuration_->logPath_;
513    }
514    /*static*/ std::string Core::getLogPathString()
515    {
516        return getInstance().configuration_->logPath_.string() + '/';
517    }
518
519    /*static*/ const boost::filesystem::path& Core::getRootPath()
520    {
521        return getInstance().configuration_->rootPath_;
522    }
523    /*static*/ std::string Core::getRootPathString()
524    {
525        return getInstance().configuration_->rootPath_.string() + '/';
526    }
527
528    /**
529    @note
530        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
531            (Object-oriented Graphics Rendering Engine)
532        For the latest info, see http://www.ogre3d.org/
533
534        Copyright (c) 2000-2008 Torus Knot Software Ltd
535
536        OGRE is licensed under the LGPL. For more info, see OGRE license.
537    */
538    void Core::setThreadAffinity(int limitToCPU)
539    {
540#ifdef ORXONOX_PLATFORM_WINDOWS
541
542        if (limitToCPU <= 0)
543            return;
544
545        unsigned int coreNr = limitToCPU - 1;
546        // Get the current process core mask
547        DWORD procMask;
548        DWORD sysMask;
549#  if _MSC_VER >= 1400 && defined (_M_X64)
550        GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
551#  else
552        GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
553#  endif
554
555        // If procMask is 0, consider there is only one core available
556        // (using 0 as procMask will cause an infinite loop below)
557        if (procMask == 0)
558            procMask = 1;
559
560        // if the core specified with coreNr is not available, take the lowest one
561        if (!(procMask & (1 << coreNr)))
562            coreNr = 0;
563
564        // Find the lowest core that this process uses and coreNr suggests
565        DWORD threadMask = 1;
566        while ((threadMask & procMask) == 0 || (threadMask < (1u << coreNr)))
567            threadMask <<= 1;
568
569        // Set affinity to the first core
570        SetThreadAffinityMask(GetCurrentThread(), threadMask);
571#endif
572    }
573
574    /**
575    @brief
576        Retrievs the executable path and sets all hard coded fixed path (currently only plugin path)
577        Also checks for "orxonox_dev_build.keep_me" in the executable diretory.
578        If found it means that this is not an installed run, hence we
579        don't write the logs and config files to ~/.orxonox
580    @throw
581        GeneralException
582    */
583    void Core::setFixedPaths()
584    {
585        //////////////////////////
586        // FIND EXECUTABLE PATH //
587        //////////////////////////
588
589#ifdef ORXONOX_PLATFORM_WINDOWS
590        // get executable module
591        TCHAR buffer[1024];
592        if (GetModuleFileName(NULL, buffer, 1024) == 0)
593            ThrowException(General, "Could not retrieve executable path.");
594
595#elif defined(ORXONOX_PLATFORM_APPLE)
596        char buffer[1024];
597        unsigned long path_len = 1023;
598        if (_NSGetExecutablePath(buffer, &path_len))
599            ThrowException(General, "Could not retrieve executable path.");
600
601#else /* Linux */
602        /* written by Nicolai Haehnle <prefect_@gmx.net> */
603
604        /* Get our PID and build the name of the link in /proc */
605        char linkname[64]; /* /proc/<pid>/exe */
606        if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", getpid()) < 0)
607        {
608            /* This should only happen on large word systems. I'm not sure
609               what the proper response is here.
610               Since it really is an assert-like condition, aborting the
611               program seems to be in order. */
612            assert(false);
613        }
614
615        /* Now read the symbolic link */
616        char buffer[1024];
617        int ret;
618        ret = readlink(linkname, buffer, 1024);
619        /* In case of an error, leave the handling up to the caller */
620        if (ret == -1)
621            ThrowException(General, "Could not retrieve executable path.");
622
623        /* Ensure proper NUL termination */
624        buffer[ret] = 0;
625#endif
626
627        configuration_->executablePath_ = boost::filesystem::path(buffer);
628#ifndef ORXONOX_PLATFORM_APPLE
629        configuration_->executablePath_ = configuration_->executablePath_.branch_path(); // remove executable name
630#endif
631
632        /////////////////////
633        // SET PLUGIN PATH //
634        /////////////////////
635
636        if (boost::filesystem::exists(configuration_->executablePath_ / "orxonox_dev_build.keep_me"))
637        {
638            COUT(1) << "Running from the build tree." << std::endl;
639            Core::bDevRun_ = true;
640            configuration_->pluginPath_ = ORXONOX_PLUGIN_DEV_PATH;
641        }
642        else
643        {
644
645#ifdef INSTALL_COPYABLE // --> relative paths
646
647            // Also set the root path
648            boost::filesystem::path relativeExecutablePath(ORXONOX_RUNTIME_INSTALL_PATH);
649            configuration_->rootPath_ = configuration_->executablePath_;
650            while (!boost::filesystem::equivalent(configuration_->rootPath_ / relativeExecutablePath, configuration_->executablePath_)
651                   && !configuration_->rootPath_.empty())
652                configuration_->rootPath_ = configuration_->rootPath_.branch_path();
653            if (configuration_->rootPath_.empty())
654                ThrowException(General, "Could not derive a root directory. Might the binary installation directory contain '..' when taken relative to the installation prefix path?");
655
656            // Plugin path is fixed as well
657            configuration_->pluginPath_ = configuration_->rootPath_ / ORXONOX_PLUGIN_INSTALL_PATH;
658
659#else
660
661            // There is no root path, so don't set it at all
662            // Plugin path is fixed as well
663            configuration_->pluginPath_ = ORXONOX_PLUGIN_INSTALL_PATH;
664
665#endif
666        }
667    }
668
669    /**
670    @brief
671        Sets config, log and media path and creates folders if necessary.
672    @throws
673        GeneralException
674    */
675    void Core::setConfigurablePaths()
676    {
677        if (Core::isDevelopmentRun())
678        {
679            configuration_->mediaPath_  = ORXONOX_MEDIA_DEV_PATH;
680            configuration_->configPath_ = ORXONOX_CONFIG_DEV_PATH;
681            configuration_->logPath_    = ORXONOX_LOG_DEV_PATH;
682        }
683        else
684        {
685
686#ifdef INSTALL_COPYABLE // --> relative paths
687
688            // Using paths relative to the install prefix, complete them
689            configuration_->mediaPath_  = configuration_->rootPath_ / ORXONOX_MEDIA_INSTALL_PATH;
690            configuration_->configPath_ = configuration_->rootPath_ / ORXONOX_CONFIG_INSTALL_PATH;
691            configuration_->logPath_    = configuration_->rootPath_ / ORXONOX_LOG_INSTALL_PATH;
692
693#else
694
695            configuration_->mediaPath_  = ORXONOX_MEDIA_INSTALL_PATH;
696
697            // Get user directory
698#  ifdef ORXONOX_PLATFORM_UNIX /* Apple? */
699            char* userDataPathPtr(getenv("HOME"));
700#  else
701            char* userDataPathPtr(getenv("APPDATA"));
702#  endif
703            if (userDataPathPtr == NULL)
704                ThrowException(General, "Could not retrieve user data path.");
705            boost::filesystem::path userDataPath(userDataPathPtr);
706            userDataPath /= ".orxonox";
707
708            configuration_->configPath_ = userDataPath / ORXONOX_CONFIG_INSTALL_PATH;
709            configuration_->logPath_    = userDataPath / ORXONOX_LOG_INSTALL_PATH;
710
711#endif
712
713        }
714
715        // Option to put all the config and log files in a separate folder
716        if (!CommandLine::getArgument("writingPathSuffix")->hasDefaultValue())
717        {
718            std::string directory(CommandLine::getValue("writingPathSuffix").getString());
719            configuration_->configPath_ = configuration_->configPath_ / directory;
720            configuration_->logPath_    = configuration_->logPath_    / directory;
721        }
722
723        // Create directories to avoid problems when opening files in non existent folders.
724        std::vector<std::pair<boost::filesystem::path, std::string> > directories;
725        directories.push_back(std::make_pair(boost::filesystem::path(configuration_->configPath_), "config"));
726        directories.push_back(std::make_pair(boost::filesystem::path(configuration_->logPath_), "log"));
727
728        for (std::vector<std::pair<boost::filesystem::path, std::string> >::iterator it = directories.begin();
729            it != directories.end(); ++it)
730        {
731            if (boost::filesystem::exists(it->first) && !boost::filesystem::is_directory(it->first))
732            {
733                ThrowException(General, std::string("The ") + it->second + " directory has been preoccupied by a file! \
734                                         Please remove " + it->first.string());
735            }
736            if (boost::filesystem::create_directories(it->first)) // function may not return true at all (bug?)
737            {
738                COUT(4) << "Created " << it->second << " directory" << std::endl;
739            }
740        }
741    }
742
743    bool Core::preUpdate(const Clock& time) throw()
744    {
745        std::string exceptionMessage;
746        try
747        {
748            if (this->bGraphicsLoaded_)
749            {
750                // process input events
751                this->inputManager_->update(time);
752                // process gui events
753                this->guiManager_->update(time);
754            }
755            // process thread commands
756            this->tclThreadManager_->update(time);
757        }
758        catch (const std::exception& ex)
759        { exceptionMessage = ex.what(); }
760        catch (...)
761        { exceptionMessage = "Unknown exception"; }
762        if (!exceptionMessage.empty())
763        {
764            COUT(0) << "An exception occurred in the Core preUpdate: " << exceptionMessage << std::endl;
765            COUT(0) << "This should really never happen! Closing the program." << std::endl;
766            return false;
767        }
768        return true;
769    }
770
771    bool Core::postUpdate(const Clock& time) throw()
772    {
773        std::string exceptionMessage;
774        try
775        {
776            if (this->bGraphicsLoaded_)
777            {
778                // Render (doesn't throw)
779                this->graphicsManager_->update(time);
780            }
781        }
782        catch (const std::exception& ex)
783        { exceptionMessage = ex.what(); }
784        catch (...)
785        { exceptionMessage = "Unknown exception"; }
786        if (!exceptionMessage.empty())
787        {
788            COUT(0) << "An exception occurred in the Core postUpdate: " << exceptionMessage << std::endl;
789            COUT(0) << "This should really never happen! Closing the program." << std::endl;
790            return false;
791        }
792        return true;
793    }
794}
Note: See TracBrowser for help on using the repository browser.