Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

New class: KeyBinderManager (yes, it really was necessary, I'm not such a Fan of zillions of classes as well) and moved the keybind command to it from GSLevel.
This new Singleton simply maps the keybind command to the right KeyBinder, selected by KeyBinderManager::setCurrent().
There is also a default KeyBinder (with keybindings.ini as file), which should do the Trick for now. Other Keybinders should only server special purposes (like in mini games or so).

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