Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/Masterserver_FS18/src/orxonox/LevelManager.cc @ 11973

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

merged branch cpp11_v3 back to trunk

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