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, 5 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
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 *      Reto Grieder
24 *   Co-authors:
25 *      Fabian 'x3n' Landau
26 *      Benjamin Knecht
27 *
28 */
29
30#include "GSLevel.h"
31#include "GSLevelMemento.h"
32
33#include <OgreCompositorManager.h>
34
35#include "util/Clock.h"
36#include "core/input/InputManager.h"
37#include "core/input/InputState.h"
38#include "core/input/KeyBinderManager.h"
39#include "core/Core.h"
40#include "core/CoreIncludes.h"
41#include "core/Game.h"
42#include "core/GameMode.h"
43#include "core/GUIManager.h"
44#include "core/Loader.h"
45#include "core/XMLFile.h"
46#include "core/command/ConsoleCommandIncludes.h"
47
48#include "LevelManager.h"
49#include "Level.h"
50#include "PlayerManager.h"
51#include "GSRoot.h"
52
53namespace orxonox
54{
55    DeclareGameState(GSLevel, "level", false, false);
56
57    static const std::string __CC_startMainMenu_name = "startMainMenu";
58    static const std::string __CC_changeGame_name = "changeGame";
59    static const std::string __CC_reloadLevel_name = "reloadLevel";
60
61    SetConsoleCommand(__CC_startMainMenu_name, &GSLevel::startMainMenu).deactivate();
62    SetConsoleCommand(__CC_changeGame_name, &GSLevel::changeGame).defaultValues("").deactivate();
63    SetConsoleCommand(__CC_reloadLevel_name, &GSLevel::reloadLevel).deactivate();
64
65    GSLevel::GSLevel(const GameStateInfo& info)
66        : GameState(info)
67        , gameInputState_(0)
68        , guiMouseOnlyInputState_(0)
69        , guiKeysOnlyInputState_(0)
70        , startFile_(0)
71        , bShowIngameGUI_(false)
72    {
73    }
74
75    GSLevel::~GSLevel()
76    {
77    }
78
79    void GSLevel::activate()
80    {
81        orxout(user_status) << "Loading level" << endl;
82
83        if (GameMode::showsGraphics())
84        {
85            gameInputState_ = InputManager::getInstance().createInputState("game");
86            gameInputState_->setMouseExclusive(true);
87            gameInputState_->setHandler(KeyBinderManager::getInstance().getDefaultAsHandler());
88            KeyBinderManager::getInstance().setToDefault();
89
90            guiMouseOnlyInputState_ = InputManager::getInstance().createInputState("guiMouseOnly");
91            guiMouseOnlyInputState_->setMouseExclusive(true);
92            guiMouseOnlyInputState_->setMouseHandler(&GUIManager::getInstance());
93
94            guiKeysOnlyInputState_ = InputManager::getInstance().createInputState("guiKeysOnly");
95            guiKeysOnlyInputState_->setKeyHandler(&GUIManager::getInstance());
96        }
97
98        this->prepareObjectTracking();
99
100        if (GameMode::isMaster())
101        {
102            this->loadLevel();
103        }
104
105        if (GameMode::showsGraphics())
106        {
107            // level is loaded: we can start capturing the input
108            InputManager::getInstance().enterState("game");
109
110            // connect the HumanPlayer to the game
111            PlayerManager::getInstance().clientConnected(0);
112
113            ModifyConsoleCommand(__CC_startMainMenu_name).activate();
114        }
115
116        if (GameMode::isStandalone())
117        {
118            ModifyConsoleCommand(__CC_changeGame_name).activate();
119            ModifyConsoleCommand(__CC_reloadLevel_name).setObject(this).activate();
120        }
121    }
122
123    void GSLevel::deactivate()
124    {
125        if (GameMode::showsGraphics())
126            InputManager::getInstance().leaveState("game");
127
128        // disconnect all HumanPlayers
129        PlayerManager::getInstance().disconnectAllClients();
130
131        if (GameMode::isMaster())
132            this->unloadLevel();
133        else
134            this->unloadLevelAsClient();
135
136        this->performObjectTracking();
137
138        if (GameMode::showsGraphics())
139        {
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
145            gameInputState_->setHandler(0);
146            guiMouseOnlyInputState_->setHandler(0);
147            guiKeysOnlyInputState_->setHandler(0);
148            InputManager::getInstance().destroyState("game");
149            InputManager::getInstance().destroyState("guiKeysOnly");
150            InputManager::getInstance().destroyState("guiMouseOnly");
151
152            ModifyConsoleCommand(__CC_startMainMenu_name  ).deactivate();
153        }
154
155        if (GameMode::isStandalone())
156        {
157            ModifyConsoleCommand(__CC_changeGame_name).deactivate();
158            ModifyConsoleCommand(__CC_reloadLevel_name).setObject(NULL).deactivate();
159        }
160    }
161
162    void GSLevel::update(const Clock& time)
163    {
164        // Note: Temporarily moved to GSRoot.
165        //// Call the scene objects
166        //for (ObjectList<Tickable>::iterator it = ObjectList<Tickable>::begin(); it; ++it)
167        //    it->tick(time.getDeltaTime() * this->timeFactor_);
168    }
169
170    void GSLevel::prepareObjectTracking()
171    {
172        for (ObjectList<BaseObject>::iterator it = ObjectList<BaseObject>::begin(); it != ObjectList<BaseObject>::end(); ++it)
173            this->staticObjects_.insert(*it);
174    }
175
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    {
196        // call the loader
197        startFile_ = new XMLFile(LevelManager::getInstance().getDefaultLevel());
198        bool loaded = Loader::getInstance().load(startFile_);
199
200        Core::getInstance().getConfig()->updateLastLevelTimestamp();
201        if(!loaded)
202            GSRoot::delayedStartMainMenu();
203    }
204
205    void GSLevel::unloadLevel()
206    {
207        Loader::getInstance().unload(startFile_);
208        delete startFile_;
209    }
210
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    {
217        for (ObjectList<Level>::iterator it = ObjectList<Level>::begin(); it != ObjectList<Level>::end(); )
218        {
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); )
221                (it++)->destroy();
222        }
223
224        for (ObjectList<Synchronisable>::iterator it = ObjectList<Synchronisable>::begin(); it != ObjectList<Synchronisable>::end(); )
225        {
226            if (it->getSyncMode() != 0x0)
227                (it++)->destroy();
228            else
229                ++it;
230        }
231    }
232
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
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    {
276        if(level != "")
277            LevelManager::getInstance().setDefaultLevel(level);
278
279        // HACK
280        Game::getInstance().popState();
281        Game::getInstance().popState();
282        Game::getInstance().requestStates("standalone, level");
283    }
284
285
286
287    ///////////////////////////////////////////////////////////////////////////
288
289    RegisterAbstractClass(GSLevelMemento).inheritsFrom<OrxonoxInterface>();
290
291    GSLevelMemento::GSLevelMemento()
292    {
293        RegisterObject(GSLevelMemento);
294    }
295}
Note: See TracBrowser for help on using the repository browser.