Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7281 was 7236, checked in by landauf, 14 years ago

replaced the temporary names of all ConsoleCommand related classes and functions by their real names

  • Property svn:eol-style set to native
File size: 13.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/Scope.h"
54#include "util/ScopedSingletonManager.h"
55#include "util/SignalHandler.h"
56#include "PathConfig.h"
57#include "CommandLineParser.h"
58#include "ConfigFileManager.h"
59#include "ConfigValueIncludes.h"
60#include "CoreIncludes.h"
61#include "DynLibManager.h"
62#include "GameMode.h"
63#include "GraphicsManager.h"
64#include "GUIManager.h"
65#include "Identifier.h"
66#include "Language.h"
67#include "LuaState.h"
68#include "command/ConsoleCommand.h"
69#include "command/IOConsole.h"
70#include "command/TclBind.h"
71#include "command/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    SetCommandLineSwitch(noIOConsole).information("Use this if you don't want to use the IOConsole (for instance for Lua debugging)");
81
82#ifdef ORXONOX_PLATFORM_WINDOWS
83    SetCommandLineArgument(limitToCPU, 1).information("Limits the program to one CPU/core (1, 2, 3, etc.). Default is the first core (faster than off)");
84#endif
85
86    Core::Core(const std::string& cmdLine)
87        // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)
88        : identifierDestroyer_(Identifier::destroyAllIdentifiers)
89        // Cleanup guard for external console commands that don't belong to an Identifier
90        , consoleCommandDestroyer_(ConsoleCommand::destroyAll)
91        , bGraphicsLoaded_(false)
92        , bStartIOConsole_(true)
93    {
94        // Set the hard coded fixed paths
95        this->pathConfig_.reset(new PathConfig());
96
97        // Create a new dynamic library manager
98        this->dynLibManager_.reset(new DynLibManager());
99
100        // Load modules
101        const std::vector<std::string>& modulePaths = this->pathConfig_->getModulePaths();
102        for (std::vector<std::string>::const_iterator it = modulePaths.begin(); it != modulePaths.end(); ++it)
103        {
104            try
105            {
106                this->dynLibManager_->load(*it);
107            }
108            catch (...)
109            {
110                COUT(1) << "Couldn't load module \"" << *it << "\": " << Exception::handleMessage() << std::endl;
111            }
112        }
113
114        // Parse command line arguments AFTER the modules have been loaded (static code!)
115        CommandLineParser::parseCommandLine(cmdLine);
116
117        // Set configurable paths like log, config and media
118        this->pathConfig_->setConfigurablePaths();
119
120        // create a signal handler (only active for Linux)
121        // This call is placed as soon as possible, but after the directories are set
122        this->signalHandler_.reset(new SignalHandler());
123        this->signalHandler_->doCatch(PathConfig::getExecutablePathString(), PathConfig::getLogPathString() + "orxonox_crash.log");
124
125        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% (Windows) was used
126        OutputHandler::getInstance().setLogPath(PathConfig::getLogPathString());
127
128        // Parse additional options file now that we know its path
129        CommandLineParser::parseFile();
130
131#ifdef ORXONOX_PLATFORM_WINDOWS
132        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
133        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
134        // the timer though).
135        int limitToCPU = CommandLineParser::getValue("limitToCPU");
136        if (limitToCPU > 0)
137            setThreadAffinity(static_cast<unsigned int>(limitToCPU));
138#endif
139
140        // Manage ini files and set the default settings file (usually orxonox.ini)
141        this->configFileManager_.reset(new ConfigFileManager());
142        this->configFileManager_->setFilename(ConfigFileType::Settings,
143            CommandLineParser::getValue("settingsFile").getString());
144
145        // Required as well for the config values
146        this->languageInstance_.reset(new Language());
147
148        // Do this soon after the ConfigFileManager has been created to open up the
149        // possibility to configure everything below here
150        ClassIdentifier<Core>::getIdentifier("Core")->initialiseObject(this, "Core", true);
151        this->setConfigValues();
152
153        // create persistent io console
154        if (CommandLineParser::getValue("noIOConsole").getBool())
155        {
156            ModifyConfigValue(bStartIOConsole_, tset, false);
157        }
158        if (this->bStartIOConsole_)
159            this->ioConsole_.reset(new IOConsole());
160
161        // creates the class hierarchy for all classes with factories
162        Identifier::createClassHierarchy();
163
164        // Load OGRE excluding the renderer and the render window
165        this->graphicsManager_.reset(new GraphicsManager(false));
166
167        // initialise Tcl
168        this->tclBind_.reset(new TclBind(PathConfig::getDataPathString()));
169        this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
170
171        // Create singletons that always exist (in other libraries)
172        this->rootScope_.reset(new Scope<ScopeID::Root>());
173    }
174
175    /**
176    @brief
177        All destruction code is handled by scoped_ptrs and ScopeGuards.
178    */
179    Core::~Core()
180    {
181        // Remove us from the object lists again to avoid problems when destroying them
182        this->unregisterObject();
183    }
184
185    //! Function to collect the SetConfigValue-macro calls.
186    void Core::setConfigValues()
187    {
188#ifdef ORXONOX_RELEASE
189        const unsigned int defaultLevelLogFile = 3;
190#else
191        const unsigned int defaultLevelLogFile = 4;
192#endif
193        SetConfigValueExternal(softDebugLevelLogFile_, "OutputHandler", "softDebugLevelLogFile", defaultLevelLogFile)
194            .description("The maximum level of debug output shown in the log file");
195        OutputHandler::getInstance().setSoftDebugLevel(OutputHandler::logFileOutputListenerName_s, this->softDebugLevelLogFile_);
196
197        SetConfigValue(language_, Language::getInstance().defaultLanguage_)
198            .description("The language of the in game text")
199            .callback(this, &Core::languageChanged);
200        SetConfigValue(bInitRandomNumberGenerator_, true)
201            .description("If true, all random actions are different each time you start the game")
202            .callback(this, &Core::initRandomNumberGenerator);
203        SetConfigValue(bStartIOConsole_, true)
204            .description("Set to false if you don't want to use the IOConsole (for Lua debugging for instance)");
205    }
206
207    //! Callback function if the language has changed.
208    void Core::languageChanged()
209    {
210        // Read the translation file after the language was configured
211        Language::getInstance().readTranslatedLanguageFile();
212    }
213
214    void Core::initRandomNumberGenerator()
215    {
216        static bool bInitialized = false;
217        if (!bInitialized && this->bInitRandomNumberGenerator_)
218        {
219            srand(static_cast<unsigned int>(time(0)));
220            rand();
221            bInitialized = true;
222        }
223    }
224
225    void Core::loadGraphics()
226    {
227        // Any exception should trigger this, even in upgradeToGraphics (see its remarks)
228        Loki::ScopeGuard unloader = Loki::MakeObjGuard(*this, &Core::unloadGraphics);
229
230        // Upgrade OGRE to receive a render window
231        try
232        {
233            graphicsManager_->upgradeToGraphics();
234        }
235        catch (...)
236        {
237            // Recovery from this is very difficult. It requires to completely
238            // destroy Ogre related objects and load again (without graphics).
239            // However since Ogre 1.7 there seems to be a problem when Ogre
240            // throws an exception and the graphics engine then gets destroyed
241            // and reloaded between throw and catch (access violation in MSVC).
242            // That's why we abort completely and only display the exception.
243            COUT(0) << "An exception occurred during upgrade to graphics. "
244                    << "That is unrecoverable. The message was:" << endl
245                    << Exception::handleMessage() << endl;
246            abort();
247        }
248
249        // Calls the InputManager which sets up the input devices.
250        inputManager_.reset(new InputManager());
251
252        // Load the CEGUI interface
253        guiManager_.reset(new GUIManager(inputManager_->getMousePosition()));
254
255        bGraphicsLoaded_ = true;
256        GameMode::bShowsGraphics_s = true;
257
258        // Load some sort of a debug overlay (only denoted by its name, "debug.oxo")
259        graphicsManager_->loadDebugOverlay();
260
261        // Create singletons associated with graphics (in other libraries)
262        graphicsScope_.reset(new Scope<ScopeID::Graphics>());
263
264        unloader.Dismiss();
265    }
266
267    void Core::unloadGraphics()
268    {
269        this->graphicsScope_.reset();
270        this->guiManager_.reset();
271        this->inputManager_.reset();
272        this->graphicsManager_.reset();
273
274        // Load Ogre::Root again, but without the render system
275        try
276            { this->graphicsManager_.reset(new GraphicsManager(false)); }
277        catch (...)
278        {
279            COUT(0) << "An exception occurred during 'unloadGraphics':" << Exception::handleMessage() << std::endl
280                    << "Another exception might be being handled which may lead to undefined behaviour!" << std::endl
281                    << "Terminating the program." << std::endl;
282            abort();
283        }
284
285        bGraphicsLoaded_ = false;
286        GameMode::bShowsGraphics_s = false;
287    }
288
289    //! Sets the language in the config-file back to the default.
290    void Core::resetLanguage()
291    {
292        ResetConfigValue(language_);
293    }
294
295    /**
296    @note
297        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
298            (Object-oriented Graphics Rendering Engine)
299        For the latest info, see http://www.ogre3d.org/
300
301        Copyright (c) 2000-2008 Torus Knot Software Ltd
302
303        OGRE is licensed under the LGPL. For more info, see OGRE license.
304    */
305    void Core::setThreadAffinity(int limitToCPU)
306    {
307#ifdef ORXONOX_PLATFORM_WINDOWS
308
309        if (limitToCPU <= 0)
310            return;
311
312        unsigned int coreNr = limitToCPU - 1;
313        // Get the current process core mask
314        DWORD procMask;
315        DWORD sysMask;
316#  if _MSC_VER >= 1400 && defined (_M_X64)
317        GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
318#  else
319        GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
320#  endif
321
322        // If procMask is 0, consider there is only one core available
323        // (using 0 as procMask will cause an infinite loop below)
324        if (procMask == 0)
325            procMask = 1;
326
327        // if the core specified with coreNr is not available, take the lowest one
328        if (!(procMask & (1 << coreNr)))
329            coreNr = 0;
330
331        // Find the lowest core that this process uses and coreNr suggests
332        DWORD threadMask = 1;
333        while ((threadMask & procMask) == 0 || (threadMask < (1u << coreNr)))
334            threadMask <<= 1;
335
336        // Set affinity to the first core
337        SetThreadAffinityMask(GetCurrentThread(), threadMask);
338#endif
339    }
340
341    void Core::preUpdate(const Clock& time)
342    {
343        // Update singletons before general ticking
344        ScopedSingletonManager::preUpdate<ScopeID::Root>(time);
345        if (this->bGraphicsLoaded_)
346        {
347            // Process input events
348            this->inputManager_->preUpdate(time);
349            // Update GUI
350            this->guiManager_->preUpdate(time);
351            // Update singletons before general ticking
352            ScopedSingletonManager::preUpdate<ScopeID::Graphics>(time);
353        }
354        // Process console events and status line
355        if (this->ioConsole_ != NULL)
356            this->ioConsole_->preUpdate(time);
357        // Process thread commands
358        this->tclThreadManager_->preUpdate(time);
359    }
360
361    void Core::postUpdate(const Clock& time)
362    {
363        // Update singletons just before rendering
364        ScopedSingletonManager::postUpdate<ScopeID::Root>(time);
365        if (this->bGraphicsLoaded_)
366        {
367            // Update singletons just before rendering
368            ScopedSingletonManager::postUpdate<ScopeID::Graphics>(time);
369            // Render (doesn't throw)
370            this->graphicsManager_->postUpdate(time);
371        }
372    }
373}
Note: See TracBrowser for help on using the repository browser.