Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Input part of the IOConsole should be working (at least with SSH on tardis). Note: removed modules from compilation

  • Property svn:eol-style set to native
File size: 16.7 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 <vector>
40
41#ifdef ORXONOX_PLATFORM_WINDOWS
42#  ifndef WIN32_LEAN_AND_MEAN
43#    define WIN32_LEAN_AND_MEAN
44#  endif
45#  include <windows.h>
46#  undef min
47#  undef max
48#endif
49
50#include "util/Clock.h"
51#include "util/Debug.h"
52#include "util/Exception.h"
53#include "util/SignalHandler.h"
54#include "PathConfig.h"
55#include "CommandExecutor.h"
56#include "CommandLine.h"
57#include "ConfigFileManager.h"
58#include "ConfigValueIncludes.h"
59#include "CoreIncludes.h"
60#include "DynLibManager.h"
61#include "GameMode.h"
62#include "GraphicsManager.h"
63#include "GUIManager.h"
64#include "Identifier.h"
65#include "Language.h"
66#include "IOConsole.h"
67#include "LuaState.h"
68#include "ScopedSingletonManager.h"
69#include "Shell.h"
70#include "TclBind.h"
71#include "TclThreadManager.h"
72#include "input/InputManager.h"
73
74namespace orxonox
75{
76    //! Static pointer to the singleton
77    Core* Core::singletonPtr_s  = 0;
78
79    SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
80#ifdef ORXONOX_PLATFORM_WINDOWS
81    SetCommandLineArgument(limitToCPU, 0).information("Limits the program to one cpu/core (1, 2, 3, etc.). 0 turns it off (default)");
82#endif
83
84    /**
85    @brief
86        Helper class for the Core singleton: we cannot derive
87        Core from OrxonoxClass because we need to handle the Identifier
88        destruction in the Core destructor.
89    */
90    class CoreConfiguration : public OrxonoxClass
91    {
92    public:
93        CoreConfiguration()
94        {
95        }
96
97        void initialise()
98        {
99            RegisterRootObject(CoreConfiguration);
100            this->setConfigValues();
101        }
102
103        /**
104            @brief Function to collect the SetConfigValue-macro calls.
105        */
106        void setConfigValues()
107        {
108#ifdef NDEBUG
109            const unsigned int defaultLevelConsole = 1;
110            const unsigned int defaultLevelLogfile = 3;
111            const unsigned int defaultLevelShell   = 1;
112#else
113            const unsigned int defaultLevelConsole = 3;
114            const unsigned int defaultLevelLogfile = 4;
115            const unsigned int defaultLevelShell   = 3;
116#endif
117            SetConfigValue(softDebugLevelConsole_, defaultLevelConsole)
118                .description("The maximal level of debug output shown in the console")
119                .callback(this, &CoreConfiguration::debugLevelChanged);
120            SetConfigValue(softDebugLevelLogfile_, defaultLevelLogfile)
121                .description("The maximal level of debug output shown in the logfile")
122                .callback(this, &CoreConfiguration::debugLevelChanged);
123            SetConfigValue(softDebugLevelShell_, defaultLevelShell)
124                .description("The maximal level of debug output shown in the ingame shell")
125                .callback(this, &CoreConfiguration::debugLevelChanged);
126
127            SetConfigValue(language_, Language::getInstance().defaultLanguage_)
128                .description("The language of the ingame text")
129                .callback(this, &CoreConfiguration::languageChanged);
130            SetConfigValue(bInitializeRandomNumberGenerator_, true)
131                .description("If true, all random actions are different each time you start the game")
132                .callback(this, &CoreConfiguration::initializeRandomNumberGenerator);
133        }
134
135        /**
136            @brief Callback function if the debug level has changed.
137        */
138        void debugLevelChanged()
139        {
140            // softDebugLevel_ is the maximum of the 3 variables
141            this->softDebugLevel_ = this->softDebugLevelConsole_;
142            if (this->softDebugLevelLogfile_ > this->softDebugLevel_)
143                this->softDebugLevel_ = this->softDebugLevelLogfile_;
144            if (this->softDebugLevelShell_ > this->softDebugLevel_)
145                this->softDebugLevel_ = this->softDebugLevelShell_;
146
147            OutputHandler::setSoftDebugLevel(OutputHandler::LD_All,     this->softDebugLevel_);
148            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Console, this->softDebugLevelConsole_);
149            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Logfile, this->softDebugLevelLogfile_);
150            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Shell,   this->softDebugLevelShell_);
151        }
152
153        /**
154            @brief Callback function if the language has changed.
155        */
156        void languageChanged()
157        {
158            // Read the translation file after the language was configured
159            Language::getInstance().readTranslatedLanguageFile();
160        }
161
162        /**
163            @brief Sets the language in the config-file back to the default.
164        */
165        void resetLanguage()
166        {
167            ResetConfigValue(language_);
168        }
169
170        void initializeRandomNumberGenerator()
171        {
172            static bool bInitialized = false;
173            if (!bInitialized && this->bInitializeRandomNumberGenerator_)
174            {
175                srand(static_cast<unsigned int>(time(0)));
176                rand();
177                bInitialized = true;
178            }
179        }
180
181        int softDebugLevel_;                            //!< The debug level
182        int softDebugLevelConsole_;                     //!< The debug level for the console
183        int softDebugLevelLogfile_;                     //!< The debug level for the logfile
184        int softDebugLevelShell_;                       //!< The debug level for the ingame shell
185        std::string language_;                          //!< The language
186        bool bInitializeRandomNumberGenerator_;         //!< If true, srand(time(0)) is called
187    };
188
189
190    Core::Core(const std::string& cmdLine)
191        // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)
192        : identifierDestroyer_(Identifier::destroyAllIdentifiers)
193        // Cleanup guard for external console commands that don't belong to an Identifier
194        , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands)
195        , configuration_(new CoreConfiguration()) // Don't yet create config values!
196        , bGraphicsLoaded_(false)
197    {
198        // Set the hard coded fixed paths
199        this->pathConfig_.reset(new PathConfig());
200
201        // Create a new dynamic library manager
202        this->dynLibManager_.reset(new DynLibManager());
203
204        // Load modules
205        const std::vector<std::string>& modulePaths = this->pathConfig_->getModulePaths();
206        for (std::vector<std::string>::const_iterator it = modulePaths.begin(); it != modulePaths.end(); ++it)
207        {
208            try
209            {
210                this->dynLibManager_->load(*it);
211            }
212            catch (...)
213            {
214                COUT(1) << "Couldn't load module \"" << *it << "\": " << Exception::handleMessage() << std::endl;
215            }
216        }
217
218        // Parse command line arguments AFTER the modules have been loaded (static code!)
219        CommandLine::parseCommandLine(cmdLine);
220
221        // Set configurable paths like log, config and media
222        this->pathConfig_->setConfigurablePaths();
223
224        // create a signal handler (only active for linux)
225        // This call is placed as soon as possible, but after the directories are set
226        this->signalHandler_.reset(new SignalHandler());
227        this->signalHandler_->doCatch(PathConfig::getExecutablePathString(), PathConfig::getLogPathString() + "orxonox_crash.log");
228
229        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% was used
230        OutputHandler::getOutStream().setLogPath(PathConfig::getLogPathString());
231
232        // Parse additional options file now that we know its path
233        CommandLine::parseFile();
234
235#ifdef ORXONOX_PLATFORM_WINDOWS
236        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
237        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
238        // the timer though).
239        int limitToCPU = CommandLine::getValue("limitToCPU");
240        if (limitToCPU > 0)
241            setThreadAffinity(static_cast<unsigned int>(limitToCPU));
242#endif
243
244        // Manage ini files and set the default settings file (usually orxonox.ini)
245        this->configFileManager_.reset(new ConfigFileManager());
246        this->configFileManager_->setFilename(ConfigFileType::Settings,
247            CommandLine::getValue("settingsFile").getString());
248
249        // Required as well for the config values
250        this->languageInstance_.reset(new Language());
251
252        // creates the class hierarchy for all classes with factories
253        Identifier::createClassHierarchy();
254
255        // Do this soon after the ConfigFileManager has been created to open up the
256        // possibility to configure everything below here
257        this->configuration_->initialise();
258
259        // Load OGRE excluding the renderer and the render window
260        this->graphicsManager_.reset(new GraphicsManager(false));
261
262        // initialise Tcl
263        this->tclBind_.reset(new TclBind(PathConfig::getDataPathString()));
264        this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
265
266        // create a shell
267        this->shell_.reset(new Shell());
268        // create persistent io console
269        this->ioConsole_.reset(new IOConsole());
270
271        // Create singletons that always exist (in other libraries)
272        this->rootScope_.reset(new Scope<ScopeID::Root>());
273    }
274
275    /**
276    @brief
277        All destruction code is handled by scoped_ptrs and ScopeGuards.
278    */
279    Core::~Core()
280    {
281    }
282
283    void Core::loadGraphics()
284    {
285        // Any exception should trigger this, even in upgradeToGraphics (see its remarks)
286        Loki::ScopeGuard unloader = Loki::MakeObjGuard(*this, &Core::unloadGraphics);
287
288        // Upgrade OGRE to receive a render window
289        graphicsManager_->upgradeToGraphics();
290
291        // Calls the InputManager which sets up the input devices.
292        inputManager_.reset(new InputManager());
293
294        // Load the CEGUI interface
295        guiManager_.reset(new GUIManager(graphicsManager_->getRenderWindow(),
296            inputManager_->getMousePosition(), graphicsManager_->isFullScreen()));
297
298        bGraphicsLoaded_ = true;
299        GameMode::bShowsGraphics_s = true;
300
301        // Load some sort of a debug overlay (only denoted by its name, "debug.oxo")
302        graphicsManager_->loadDebugOverlay();
303
304        // Create singletons associated with graphics (in other libraries)
305        graphicsScope_.reset(new Scope<ScopeID::Graphics>());
306
307        unloader.Dismiss();
308    }
309
310    void Core::unloadGraphics()
311    {
312        this->graphicsScope_.reset();
313        this->guiManager_.reset();
314        this->inputManager_.reset();
315        this->graphicsManager_.reset();
316
317        // Load Ogre::Root again, but without the render system
318        try
319            { this->graphicsManager_.reset(new GraphicsManager(false)); }
320        catch (...)
321        {
322            COUT(0) << "An exception occurred during 'unloadGraphics':" << Exception::handleMessage() << std::endl
323                    << "Another exception might be being handled which may lead to undefined behaviour!" << std::endl
324                    << "Terminating the program." << std::endl;
325            abort();
326        }
327
328        bGraphicsLoaded_ = false;
329        GameMode::bShowsGraphics_s = false;
330    }
331
332    /**
333        @brief Returns the softDebugLevel for the given device (returns a default-value if the class is right about to be created).
334        @param device The device
335        @return The softDebugLevel
336    */
337    /*static*/ int Core::getSoftDebugLevel(OutputHandler::OutputDevice device)
338    {
339        switch (device)
340        {
341        case OutputHandler::LD_All:
342            return Core::getInstance().configuration_->softDebugLevel_;
343        case OutputHandler::LD_Console:
344            return Core::getInstance().configuration_->softDebugLevelConsole_;
345        case OutputHandler::LD_Logfile:
346            return Core::getInstance().configuration_->softDebugLevelLogfile_;
347        case OutputHandler::LD_Shell:
348            return Core::getInstance().configuration_->softDebugLevelShell_;
349        default:
350            assert(0);
351            return 2;
352        }
353    }
354
355     /**
356        @brief Sets the softDebugLevel for the given device. Please use this only temporary and restore the value afterwards, as it overrides the configured value.
357        @param device The device
358        @param level The level
359    */
360    /*static*/ void Core::setSoftDebugLevel(OutputHandler::OutputDevice device, int level)
361    {
362        if (device == OutputHandler::LD_All)
363            Core::getInstance().configuration_->softDebugLevel_ = level;
364        else if (device == OutputHandler::LD_Console)
365            Core::getInstance().configuration_->softDebugLevelConsole_ = level;
366        else if (device == OutputHandler::LD_Logfile)
367            Core::getInstance().configuration_->softDebugLevelLogfile_ = level;
368        else if (device == OutputHandler::LD_Shell)
369            Core::getInstance().configuration_->softDebugLevelShell_ = level;
370
371        OutputHandler::setSoftDebugLevel(device, level);
372    }
373
374    /**
375        @brief Returns the configured language.
376    */
377    /*static*/ const std::string& Core::getLanguage()
378    {
379        return Core::getInstance().configuration_->language_;
380    }
381
382    /**
383        @brief Sets the language in the config-file back to the default.
384    */
385    /*static*/ void Core::resetLanguage()
386    {
387        Core::getInstance().configuration_->resetLanguage();
388    }
389
390    /**
391    @note
392        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
393            (Object-oriented Graphics Rendering Engine)
394        For the latest info, see http://www.ogre3d.org/
395
396        Copyright (c) 2000-2008 Torus Knot Software Ltd
397
398        OGRE is licensed under the LGPL. For more info, see OGRE license.
399    */
400    void Core::setThreadAffinity(int limitToCPU)
401    {
402#ifdef ORXONOX_PLATFORM_WINDOWS
403
404        if (limitToCPU <= 0)
405            return;
406
407        unsigned int coreNr = limitToCPU - 1;
408        // Get the current process core mask
409        DWORD procMask;
410        DWORD sysMask;
411#  if _MSC_VER >= 1400 && defined (_M_X64)
412        GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
413#  else
414        GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
415#  endif
416
417        // If procMask is 0, consider there is only one core available
418        // (using 0 as procMask will cause an infinite loop below)
419        if (procMask == 0)
420            procMask = 1;
421
422        // if the core specified with coreNr is not available, take the lowest one
423        if (!(procMask & (1 << coreNr)))
424            coreNr = 0;
425
426        // Find the lowest core that this process uses and coreNr suggests
427        DWORD threadMask = 1;
428        while ((threadMask & procMask) == 0 || (threadMask < (1u << coreNr)))
429            threadMask <<= 1;
430
431        // Set affinity to the first core
432        SetThreadAffinityMask(GetCurrentThread(), threadMask);
433#endif
434    }
435
436    void Core::preUpdate(const Clock& time)
437    {
438        // singletons from other libraries
439        ScopedSingletonManager::update<ScopeID::Root>(time);
440        if (this->bGraphicsLoaded_)
441        {
442            // process input events
443            this->inputManager_->update(time);
444            // process gui events
445            this->guiManager_->update(time);
446            // graphics singletons from other libraries
447            ScopedSingletonManager::update<ScopeID::Graphics>(time);
448        }
449        // process console text
450        this->ioConsole_->update(time);
451        // process thread commands
452        this->tclThreadManager_->update(time);
453    }
454
455    void Core::postUpdate(const Clock& time)
456    {
457        if (this->bGraphicsLoaded_)
458        {
459            // Render (doesn't throw)
460            this->graphicsManager_->update(time);
461        }
462    }
463}
Note: See TracBrowser for help on using the repository browser.