Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/LevelManager.cc @ 9550

Last change on this file since 9550 was 9550, checked in by landauf, 11 years ago

merged testing branch back to trunk. unbelievable it took me 13 months to finish this chore…

  • Property svn:eol-style set to native
File size: 10.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 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      Damian 'Mozork' Frick
26 *
27 */
28
29/**
30    @file LevelManager.cc
31    @brief Implementation of the LevelManager singleton.
32*/
33
34#include "LevelManager.h"
35
36#include <map>
37
38#include "util/ScopedSingletonManager.h"
39#include "core/ClassTreeMask.h"
40#include "core/CommandLineParser.h"
41#include "core/ConfigValueIncludes.h"
42#include "core/CoreIncludes.h"
43#include "core/Loader.h"
44#include "core/Resource.h"
45#include "core/XMLFile.h"
46#include "Level.h"
47#include "PlayerManager.h"
48
49namespace orxonox
50{
51    SetCommandLineArgument(level, "").shortcut("l").information("Default level file (overrides LevelManager::defaultLevelName_ configValue)");
52
53    ManageScopedSingleton(LevelManager, ScopeID::Root, false);
54
55    /**
56    @brief
57        Constructor. Registers the object, sets config values and initializes variables.
58    */
59    LevelManager::LevelManager()
60    {
61        RegisterRootObject(LevelManager);
62        this->setConfigValues();
63
64        // check override
65        if (!CommandLineParser::getArgument("level")->hasDefaultValue())
66        {
67            ModifyConfigValue(defaultLevelName_, tset, CommandLineParser::getValue("level").get<std::string>());
68        }
69
70        this->compileAvailableLevelList();
71        this->nextIndex_ = 0;
72        this->nextLevel_ = this->availableLevels_.begin();
73    }
74
75    LevelManager::~LevelManager()
76    {
77        // Delete all the LevelInfoItem objects because the LevelManager created them
78        std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = availableLevels_.begin();
79        for (; it != availableLevels_.end(); ++it)
80            delete *it;
81    }
82
83    /**
84    @brief
85        Set the config values for this object.
86    */
87    void LevelManager::setConfigValues()
88    {
89        SetConfigValue(defaultLevelName_, "missionOne.oxw")
90            .description("Sets the pre selection of the level in the main menu.");
91    }
92
93    /**
94    @brief
95        Request activity for the input Level.
96        The Level will be added to the list of Levels whose activity is requested. The list is accessed in a FIFO manner.
97        If the Level is the only Level in the list it will be immediately activated. If not it will be activated as soon as it reaches the front of the list.
98    @param level
99        A pointer to the Level whose activity is requested.
100    */
101    void LevelManager::requestActivity(Level* level)
102    {
103        assert( std::find(this->levels_.begin(), this->levels_.end(), level)==this->levels_.end() );
104        // If the level is already in list.
105        if( std::find(this->levels_.begin(), this->levels_.end(), level)!=this->levels_.end() )
106            return;
107        // If it isn't insert it at the back.
108        this->levels_.push_back(level);
109        // If it is the only level in the list activate it.
110        if (this->levels_.size() == 1)
111            this->activateNextLevel();
112    }
113
114    /**
115    @brief
116        Release activity for the input Level.
117        Removes the Level from the list. If the Level was the one currently active, it is deactivated and the next Level in line is activated.
118    @param level
119        A pointer to the Level whose activity is to be released.
120    */
121    void LevelManager::releaseActivity(Level* level)
122    {
123        if (this->levels_.size() > 0)
124        {
125            // If the level is the active level in the front of the list.
126            if (this->levels_.front() == level)
127            {
128                // Deactivate it, remove it from the list and activate the next level in line.
129                level->setActive(false);
130                this->levels_.pop_front();
131                this->activateNextLevel();
132            }
133            else // Else just remove it from the list.
134                this->levels_.erase(std::find(this->levels_.begin(), this->levels_.end(), level));
135        }
136    }
137
138    /**
139    @brief
140        Get the currently active Level.
141    @return
142        Returns a pointer to the currently active level or NULL if there currently are no active Levels.
143    */
144    Level* LevelManager::getActiveLevel()
145    {
146        if (this->levels_.size() > 0)
147            return this->levels_.front();
148        else
149            return 0;
150    }
151
152    /**
153    @brief
154        Activate the next Level.
155    */
156    void LevelManager::activateNextLevel()
157    {
158        if (this->levels_.size() > 0)
159        {
160            // Activate the level that is the first in the list of levels whose activity has been requested.
161            this->levels_.front()->setActive(true);
162            // Make every player enter the newly activated level.
163            for (std::map<unsigned int, PlayerInfo*>::const_iterator it = PlayerManager::getInstance().getClients().begin(); it != PlayerManager::getInstance().getClients().end(); ++it)
164                this->levels_.front()->playerEntered(it->second);
165        }
166    }
167
168    /**
169    @brief
170        Set the default Level.
171    @param levelName
172        The filename of the default Level.
173    */
174    void LevelManager::setDefaultLevel(const std::string& levelName)
175    {
176        ModifyConfigValue(defaultLevelName_, set, levelName);
177    }
178
179    /**
180    @brief
181        Get the number of available Levels.
182        Also updates the list of available Levels.
183    @return
184        Returns the number of available Levels.
185    */
186    unsigned int LevelManager::getNumberOfLevels()
187    {
188        this->updateAvailableLevelList();
189
190        return this->availableLevels_.size();
191    }
192
193    /**
194    @brief
195        Get the LevelInfoItem at the given index in the list of available Levels.
196        The LevelInfoItems are sorted in alphabetical order accoridng to the name of the Level.
197        This method is most efficiently called with consecutive indices (or at least ascending indices).
198    @param index
199        The index of the item that should be returned.
200    @return
201        Returns a pointer to the LevelInfoItem at the given index.
202    */
203    LevelInfoItem* LevelManager::getAvailableLevelListItem(unsigned int index)
204    {
205        if(index >= this->availableLevels_.size())
206            return NULL;
207
208        // If this index directly follows the last we can optimize a lot.
209        if(index == this->nextIndex_)
210        {
211            this->nextIndex_++;
212            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
213            this->nextLevel_++;
214            return *it;
215        }
216        else
217        {
218            // If this index is bigger than the last, we can optimize a little.
219            if(index < this->nextIndex_)
220            {
221                this->nextIndex_ = 0;
222                this->nextLevel_ = this->availableLevels_.begin();
223            }
224
225            while(this->nextIndex_ != index)
226            {
227                this->nextIndex_++;
228                this->nextLevel_++;
229            }
230            this->nextIndex_++;
231            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
232            this->nextLevel_++;
233            return *it;
234        }
235    }
236
237    /**
238    @brief
239        Compile the list of available Levels.
240        Iterates over all *.oxw files, loads the LevelInfo objects in them and from that it creates the LevelInfoItems which are inserted in a list.
241    */
242    void LevelManager::compileAvailableLevelList()
243    {
244        // Get all files matching the level criteria
245        Ogre::StringVectorPtr levels = Resource::findResourceNames("*.oxw");
246
247        // We only want to load as little as possible
248        ClassTreeMask mask;
249        mask.exclude(Class(BaseObject));
250        mask.include(Class(LevelInfo));
251
252        // Iterate over all the found *.oxw files
253        orxout(internal_info) << "Loading LevelInfos..." << endl;
254        std::set<std::string> names;
255        for (Ogre::StringVector::const_iterator it = levels->begin(); it != levels->end(); ++it)
256        {
257            // TODO: Replace with tag?
258            if (it->find("old/") != 0)
259            {
260                LevelInfoItem* info = NULL;
261
262                // Load the LevelInfo object from the level file.
263                XMLFile file = XMLFile(*it);
264                Loader::load(&file, mask, false, true);
265
266                // Find the LevelInfo object we've just loaded (if there was one)
267                for(ObjectList<LevelInfo>::iterator item = ObjectList<LevelInfo>::begin(); item != ObjectList<LevelInfo>::end(); ++item)
268                    if(item->getXMLFilename() == *it)
269                        info = item->copy();
270
271                // We don't need the loaded stuff anymore
272                Loader::unload(&file);
273
274                if(info == NULL)
275                {
276                    // Create a default LevelInfoItem object that merely contains the name
277                    std::string filenameWOExtension = it->substr(0, it->find(".oxw"));
278                    info = new LevelInfoItem(filenameWOExtension, *it);
279                }
280
281                // Warn about levels with the same name.
282                if(!names.insert(info->getName()).second)
283                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with name '" << info->getName() << "' found!" << endl;
284
285                // Warn about multiple items so that it gets fixed quickly
286                if(availableLevels_.find(info) != availableLevels_.end())
287                {
288                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with same name '" << info->getName() << "' and filename found! Exluding..." << endl;
289                    // Delete LevelInfoItem to avoid a dangling pointer
290                    delete info;
291                }
292                else
293                    this->availableLevels_.insert(info);
294            }
295        }
296    }
297
298    /**
299    @brief
300        Update the list of available Levels.
301    */
302    void LevelManager::updateAvailableLevelList(void)
303    {
304        //TODO: Implement some kind of update?
305    }
306}
Note: See TracBrowser for help on using the repository browser.