Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/orxonox/gamestates/GSLevel.cc @ 10569

Last change on this file since 10569 was 10569, checked in by landauf, 9 years ago

fixed bug which was introduced in r10563: when unloading in client mode, the Level object was not destroyed because it was still referenced by MeshLodInformation instances (which are not Synchronizables). Now the level is unloaded correctly even in client mode.

  • Property svn:eol-style set to native
File size: 9.6 KB
RevLine 
[1661]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 *      Reto Grieder
24 *   Co-authors:
[1662]25 *      Fabian 'x3n' Landau
[2896]26 *      Benjamin Knecht
[1661]27 *
28 */
29
30#include "GSLevel.h"
[10281]31#include "GSLevelMemento.h"
[1661]32
[5695]33#include <OgreCompositorManager.h>
34
[5855]35#include "util/Clock.h"
[1661]36#include "core/input/InputManager.h"
[3327]37#include "core/input/InputState.h"
[5863]38#include "core/input/KeyBinderManager.h"
[7870]39#include "core/Core.h"
[10281]40#include "core/CoreIncludes.h"
[2896]41#include "core/Game.h"
42#include "core/GameMode.h"
[3370]43#include "core/GUIManager.h"
[3196]44#include "core/Loader.h"
45#include "core/XMLFile.h"
[10347]46#include "core/command/ConsoleCommandIncludes.h"
[3196]47
[2087]48#include "LevelManager.h"
[10569]49#include "Level.h"
[2662]50#include "PlayerManager.h"
[8079]51#include "GSRoot.h"
[1661]52
53namespace orxonox
54{
[3370]55    DeclareGameState(GSLevel, "level", false, false);
[1934]56
[7876]57    static const std::string __CC_startMainMenu_name = "startMainMenu";
58    static const std::string __CC_changeGame_name = "changeGame";
[10281]59    static const std::string __CC_reloadLevel_name = "reloadLevel";
[7876]60
61    SetConsoleCommand(__CC_startMainMenu_name, &GSLevel::startMainMenu).deactivate();
[8079]62    SetConsoleCommand(__CC_changeGame_name, &GSLevel::changeGame).defaultValues("").deactivate();
[10281]63    SetConsoleCommand(__CC_reloadLevel_name, &GSLevel::reloadLevel).deactivate();
[7876]64
[3370]65    GSLevel::GSLevel(const GameStateInfo& info)
66        : GameState(info)
[2896]67        , gameInputState_(0)
68        , guiMouseOnlyInputState_(0)
69        , guiKeysOnlyInputState_(0)
[5876]70        , startFile_(0)
[6417]71        , bShowIngameGUI_(false)
[1661]72    {
73    }
74
75    GSLevel::~GSLevel()
76    {
77    }
78
[2896]79    void GSLevel::activate()
[1661]80    {
[8858]81        orxout(user_status) << "Loading level" << endl;
82
[2896]83        if (GameMode::showsGraphics())
[2087]84        {
[3327]85            gameInputState_ = InputManager::getInstance().createInputState("game");
[8729]86            gameInputState_->setMouseExclusive(true);
[5863]87            gameInputState_->setHandler(KeyBinderManager::getInstance().getDefaultAsHandler());
88            KeyBinderManager::getInstance().setToDefault();
[1661]89
[3327]90            guiMouseOnlyInputState_ = InputManager::getInstance().createInputState("guiMouseOnly");
[8729]91            guiMouseOnlyInputState_->setMouseExclusive(true);
[6746]92            guiMouseOnlyInputState_->setMouseHandler(&GUIManager::getInstance());
[2896]93
[3327]94            guiKeysOnlyInputState_ = InputManager::getInstance().createInputState("guiKeysOnly");
[6746]95            guiKeysOnlyInputState_->setKeyHandler(&GUIManager::getInstance());
[2087]96        }
[1662]97
[10566]98        this->prepareObjectTracking();
99
[2896]100        if (GameMode::isMaster())
[2087]101        {
102            this->loadLevel();
103        }
[1755]104
[2896]105        if (GameMode::showsGraphics())
[2087]106        {
107            // level is loaded: we can start capturing the input
[3327]108            InputManager::getInstance().enterState("game");
[6417]109
[5820]110            // connect the HumanPlayer to the game
[5850]111            PlayerManager::getInstance().clientConnected(0);
[7876]112
113            ModifyConsoleCommand(__CC_startMainMenu_name).activate();
[2087]114        }
[7876]115
116        if (GameMode::isStandalone())
[10281]117        {
[7876]118            ModifyConsoleCommand(__CC_changeGame_name).activate();
[10281]119            ModifyConsoleCommand(__CC_reloadLevel_name).setObject(this).activate();
120        }
[2662]121    }
[2087]122
[2896]123    void GSLevel::deactivate()
124    {
[5695]125        if (GameMode::showsGraphics())
[3327]126            InputManager::getInstance().leaveState("game");
[6417]127
[5966]128        // disconnect all HumanPlayers
129        PlayerManager::getInstance().disconnectAllClients();
[1662]130
[2896]131        if (GameMode::isMaster())
[2087]132            this->unloadLevel();
[10566]133        else
134            this->unloadLevelAsClient();
[1662]135
[10566]136        this->performObjectTracking();
137
[2896]138        if (GameMode::showsGraphics())
[2087]139        {
[7879]140#if OGRE_VERSION < 0x010700
141            // unload all compositors (this is only necessary because we don't yet destroy all resources!)
142            Ogre::CompositorManager::getSingleton().removeAll();
143#endif
144
[2896]145            gameInputState_->setHandler(0);
146            guiMouseOnlyInputState_->setHandler(0);
147            guiKeysOnlyInputState_->setHandler(0);
[3327]148            InputManager::getInstance().destroyState("game");
[5818]149            InputManager::getInstance().destroyState("guiKeysOnly");
150            InputManager::getInstance().destroyState("guiMouseOnly");
[7876]151
152            ModifyConsoleCommand(__CC_startMainMenu_name  ).deactivate();
[2087]153        }
[7876]154
155        if (GameMode::isStandalone())
[10281]156        {
[7876]157            ModifyConsoleCommand(__CC_changeGame_name).deactivate();
[10281]158            ModifyConsoleCommand(__CC_reloadLevel_name).setObject(NULL).deactivate();
159        }
[1661]160    }
161
[2896]162    void GSLevel::update(const Clock& time)
[1661]163    {
[5876]164        // Note: Temporarily moved to GSRoot.
[2087]165        //// Call the scene objects
166        //for (ObjectList<Tickable>::iterator it = ObjectList<Tickable>::begin(); it; ++it)
167        //    it->tick(time.getDeltaTime() * this->timeFactor_);
[1661]168    }
169
[10566]170    void GSLevel::prepareObjectTracking()
[1670]171    {
[5922]172        for (ObjectList<BaseObject>::iterator it = ObjectList<BaseObject>::begin(); it != ObjectList<BaseObject>::end(); ++it)
173            this->staticObjects_.insert(*it);
[10566]174    }
[6417]175
[10566]176    void GSLevel::performObjectTracking()
177    {
178        orxout(internal_info) << "Remaining objects:" << endl;
179        unsigned int i = 0;
180        for (ObjectList<BaseObject>::iterator it = ObjectList<BaseObject>::begin(); it != ObjectList<BaseObject>::end(); ++it)
181        {
182            std::set<BaseObject*>::const_iterator find = this->staticObjects_.find(*it);
183            if (find == this->staticObjects_.end())
184            {
185                orxout(internal_warning) << ++i << ": " << it->getIdentifier()->getName() << " (" << *it << "), references: " << it->getReferenceCount() << endl;
186            }
187        }
188        if (i == 0)
189            orxout(internal_info) << i << " objects remaining. Well done!" << endl;
190        else
191            orxout(internal_warning) << i << " objects remaining. Try harder!" << endl;
192    }
193
194    void GSLevel::loadLevel()
195    {
[1670]196        // call the loader
[5876]197        startFile_ = new XMLFile(LevelManager::getInstance().getDefaultLevel());
[10508]198        bool loaded = Loader::getInstance().load(startFile_);
[7870]199
[10479]200        Core::getInstance().getConfig()->updateLastLevelTimestamp();
[8079]201        if(!loaded)
202            GSRoot::delayedStartMainMenu();
[1670]203    }
204
205    void GSLevel::unloadLevel()
206    {
[10392]207        Loader::getInstance().unload(startFile_);
[5876]208        delete startFile_;
[10566]209    }
[5922]210
[10566]211    /**
212     * Unloads a level when the game instance is (or was) a client in a multiplayer session.
213     * In this case, cleanup after unloading a level is done differently because certain things (e.g. the xml file) are unknown.
214     */
215    void GSLevel::unloadLevelAsClient()
216    {
[10569]217        for (ObjectList<Level>::iterator it = ObjectList<Level>::begin(); it != ObjectList<Level>::end(); )
[5922]218        {
[10569]219            StrongPtr<Level> level = *(it++); // StrongPtr prevents that the Level gets destroyed while we loop over it
220            for (ObjectList<BaseObject>::iterator it = ObjectList<BaseObject>::begin(level); it != ObjectList<BaseObject>::end(level); )
[10566]221                (it++)->destroy();
[10569]222        }
223
224        for (ObjectList<Synchronisable>::iterator it = ObjectList<Synchronisable>::begin(); it != ObjectList<Synchronisable>::end(); )
225        {
226            if (it->getSyncMode() != 0x0)
227                (it++)->destroy();
[10566]228            else
229                ++it;
[5922]230        }
[1670]231    }
[7876]232
[10281]233    void GSLevel::reloadLevel()
234    {
235        // export all states
236        std::vector<GSLevelMementoState*> states;
237        for (ObjectList<GSLevelMemento>::iterator it = ObjectList<GSLevelMemento>::begin(); it != ObjectList<GSLevelMemento>::end(); ++it)
238        {
239            GSLevelMementoState* state = it->exportMementoState();
240            if (state)
241                states.push_back(state);
242        }
243
244        // reload level (or better: reload the whole gamestate)
245        this->deactivate();
246        this->activate();
247
248        // import all states
249        for (ObjectList<GSLevelMemento>::iterator it = ObjectList<GSLevelMemento>::begin(); it != ObjectList<GSLevelMemento>::end(); ++it)
250            it->importMementoState(states);
251
252        // delete states
253        for (size_t i = 0; i < states.size(); ++i)
254            delete states[i];
255    }
256
[7876]257    /**
258    @brief
259        Starts the MainMenu.
260    */
261    /*static*/ void GSLevel::startMainMenu(void)
262    {
263        // HACK
264        Game::getInstance().popState();
265        Game::getInstance().popState();
266    }
267
268    /**
269    @brief
270        Terminates the current game and starts a new game.
271    @param level
272        The filename of the level to be started.
273    */
274    /*static*/ void GSLevel::changeGame(const std::string& level)
275    {
[8079]276        if(level != "")
[7876]277            LevelManager::getInstance().setDefaultLevel(level);
278
279        // HACK
280        Game::getInstance().popState();
281        Game::getInstance().popState();
282        Game::getInstance().requestStates("standalone, level");
283    }
[10281]284
285
286
287    ///////////////////////////////////////////////////////////////////////////
288
[10362]289    RegisterAbstractClass(GSLevelMemento).inheritsFrom<OrxonoxInterface>();
[10281]290
291    GSLevelMemento::GSLevelMemento()
292    {
293        RegisterObject(GSLevelMemento);
294    }
[1661]295}
Note: See TracBrowser for help on using the repository browser.