Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged branch core7 back to trunk

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