Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10404 was 10258, checked in by landauf, 10 years ago

merged presentationHS14merge back to trunk

  • Property svn:eol-style set to native
File size: 11.1 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/config/CommandLineParser.h"
40#include "core/config/ConfigValueIncludes.h"
41#include "core/CoreIncludes.h"
42#include "core/ClassTreeMask.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        RegisterObject(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        SetConfigValue(lastFinishedCampaignMission_,  "")
92            .description("The last finished mission of a campaign");
93        SetConfigValue(campaignMissions_,  std::vector<std::string>())
94            .description("The list of missions in the campaign");
95    }
96
97    /**
98     * @brief Stores the argument in the corresponding config value.
99     */
100    void LevelManager::setLastFinishedCampaignMission(const std::string& lastFinishedCampaignMission)
101    {
102        ModifyConfigValue(lastFinishedCampaignMission_, set, lastFinishedCampaignMission);
103    }
104
105    /**
106    @brief
107        Request activity for the input Level.
108        The Level will be added to the list of Levels whose activity is requested. The list is accessed in a FIFO manner.
109        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.
110    @param level
111        A pointer to the Level whose activity is requested.
112    */
113    void LevelManager::requestActivity(Level* level)
114    {
115        assert( std::find(this->levels_.begin(), this->levels_.end(), level)==this->levels_.end() );
116        // If the level is already in list.
117        if( std::find(this->levels_.begin(), this->levels_.end(), level)!=this->levels_.end() )
118            return;
119        // If it isn't insert it at the back.
120        this->levels_.push_back(level);
121        // If it is the only level in the list activate it.
122        if (this->levels_.size() == 1)
123            this->activateNextLevel();
124    }
125
126    /**
127    @brief
128        Release activity for the input Level.
129        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.
130    @param level
131        A pointer to the Level whose activity is to be released.
132    */
133    void LevelManager::releaseActivity(Level* level)
134    {
135        if (this->levels_.size() > 0)
136        {
137            // If the level is the active level in the front of the list.
138            if (this->levels_.front() == level)
139            {
140                // Deactivate it, remove it from the list and activate the next level in line.
141                level->setActive(false);
142                this->levels_.pop_front();
143                this->activateNextLevel();
144            }
145            else // Else just remove it from the list.
146                this->levels_.erase(std::find(this->levels_.begin(), this->levels_.end(), level));
147        }
148    }
149
150    /**
151    @brief
152        Get the currently active Level.
153    @return
154        Returns a pointer to the currently active level or NULL if there currently are no active Levels.
155    */
156    Level* LevelManager::getActiveLevel()
157    {
158        if (this->levels_.size() > 0)
159            return this->levels_.front();
160        else
161            return 0;
162    }
163
164    /**
165    @brief
166        Activate the next Level.
167    */
168    void LevelManager::activateNextLevel()
169    {
170        if (this->levels_.size() > 0)
171        {
172            // Activate the level that is the first in the list of levels whose activity has been requested.
173            this->levels_.front()->setActive(true);
174            // Make every player enter the newly activated level.
175            for (std::map<unsigned int, PlayerInfo*>::const_iterator it = PlayerManager::getInstance().getClients().begin(); it != PlayerManager::getInstance().getClients().end(); ++it)
176                this->levels_.front()->playerEntered(it->second);
177        }
178    }
179
180    /**
181    @brief
182        Set the default Level.
183    @param levelName
184        The filename of the default Level.
185    */
186    void LevelManager::setDefaultLevel(const std::string& levelName)
187    {
188        ModifyConfigValue(defaultLevelName_, set, levelName);
189    }
190
191    /**
192    @brief
193        Get the number of available Levels.
194        Also updates the list of available Levels.
195    @return
196        Returns the number of available Levels.
197    */
198    unsigned int LevelManager::getNumberOfLevels()
199    {
200        this->updateAvailableLevelList();
201
202        return this->availableLevels_.size();
203    }
204
205    /**
206    @brief
207        Get the LevelInfoItem at the given index in the list of available Levels.
208        The LevelInfoItems are sorted in alphabetical order accoridng to the name of the Level.
209        This method is most efficiently called with consecutive indices (or at least ascending indices).
210    @param index
211        The index of the item that should be returned.
212    @return
213        Returns a pointer to the LevelInfoItem at the given index.
214    */
215    LevelInfoItem* LevelManager::getAvailableLevelListItem(unsigned int index)
216    {
217        if(index >= this->availableLevels_.size())
218            return NULL;
219
220        // If this index directly follows the last we can optimize a lot.
221        if(index == this->nextIndex_)
222        {
223            this->nextIndex_++;
224            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
225            this->nextLevel_++;
226            return *it;
227        }
228        else
229        {
230            // If this index is bigger than the last, we can optimize a little.
231            if(index < this->nextIndex_)
232            {
233                this->nextIndex_ = 0;
234                this->nextLevel_ = this->availableLevels_.begin();
235            }
236
237            while(this->nextIndex_ != index)
238            {
239                this->nextIndex_++;
240                this->nextLevel_++;
241            }
242            this->nextIndex_++;
243            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
244            this->nextLevel_++;
245            return *it;
246        }
247    }
248
249    /**
250    @brief
251        Compile the list of available Levels.
252        Iterates over all *.oxw files, loads the LevelInfo objects in them and from that it creates the LevelInfoItems which are inserted in a list.
253    */
254    void LevelManager::compileAvailableLevelList()
255    {
256        // Get all files matching the level criteria
257        Ogre::StringVectorPtr levels = Resource::findResourceNames("*.oxw");
258
259        // We only want to load as little as possible
260        ClassTreeMask mask;
261        mask.exclude(Class(BaseObject));
262        mask.include(Class(LevelInfo));
263
264        // Iterate over all the found *.oxw files
265        orxout(internal_info) << "Loading LevelInfos..." << endl;
266        std::set<std::string> names;
267        for (Ogre::StringVector::const_iterator it = levels->begin(); it != levels->end(); ++it)
268        {
269            // TODO: Replace with tag?
270            if (it->find("old/") != 0)
271            {
272                LevelInfoItem* info = NULL;
273
274                // Load the LevelInfo object from the level file.
275                XMLFile file = XMLFile(*it);
276                Loader::load(&file, mask, false, true);
277
278                // Find the LevelInfo object we've just loaded (if there was one)
279                for(ObjectList<LevelInfo>::iterator item = ObjectList<LevelInfo>::begin(); item != ObjectList<LevelInfo>::end(); ++item)
280                    if(item->getXMLFilename() == *it)
281                        info = item->copy();
282
283                // We don't need the loaded stuff anymore
284                Loader::unload(&file);
285
286                if(info == NULL)
287                {
288                    // Create a default LevelInfoItem object that merely contains the name
289                    std::string filenameWOExtension = it->substr(0, it->find(".oxw"));
290                    info = new LevelInfoItem(filenameWOExtension, *it);
291                }
292
293                // Warn about levels with the same name.
294                if(!names.insert(info->getName()).second)
295                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with name '" << info->getName() << "' found!" << endl;
296
297                // Warn about multiple items so that it gets fixed quickly
298                if(availableLevels_.find(info) != availableLevels_.end())
299                {
300                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with same name '" << info->getName() << "' and filename found! Exluding..." << endl;
301                    // Delete LevelInfoItem to avoid a dangling pointer
302                    delete info;
303                }
304                else
305                    this->availableLevels_.insert(info);
306            }
307        }
308    }
309
310    /**
311    @brief
312        Update the list of available Levels.
313    */
314    void LevelManager::updateAvailableLevelList(void)
315    {
316        //TODO: Implement some kind of update?
317    }
318}
Note: See TracBrowser for help on using the repository browser.