Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/usability/src/orxonox/LevelManager.cc @ 7978

Last change on this file since 7978 was 7963, checked in by rgrieder, 14 years ago

Added "replaceLuaTags" function to the Loader. That allows to load files without parsing it as Lua file.
Bottom line:

  • Compiling the level list is about 30 times faster and takes less than half a second now
  • We need to write level files that are XML-valid even if all the Lua stuff is removed. (or: somebody find a better implementation for speeding up that LevelInfo loading)
  • 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 *      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").getString());
68        }
69
70        this->compileAvailableLevelList();
71        this->nextIndex_ = 0;
72        this->nextLevel_ = this->availableLevels_.begin();
73    }
74
75    LevelManager::~LevelManager()
76    {
77    }
78
79    /**
80    @brief
81        Set the config values for this object.
82    */
83    void LevelManager::setConfigValues()
84    {
85        SetConfigValue(defaultLevelName_, "presentationDM.oxw")
86            .description("Sets the pre selection of the level in the main menu.");
87    }
88
89    /**
90    @brief
91        Request activity for the input Level.
92        The Level will be added to the list of Levels whose activity is requested. The list is accessed in a FIFO manner.
93        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.
94    @param level
95        A pointer to the Level whose activity is requested.
96    */
97    void LevelManager::requestActivity(Level* level)
98    {
99        assert( std::find(this->levels_.begin(), this->levels_.end(), level)==this->levels_.end() );
100        // If the level is already in list.
101        if( std::find(this->levels_.begin(), this->levels_.end(), level)!=this->levels_.end() )
102            return;
103        // If it isn't insert it at the back.
104        this->levels_.push_back(level);
105        // If it is the only level in the list activate it.
106        if (this->levels_.size() == 1)
107            this->activateNextLevel();
108    }
109
110    /**
111    @brief
112        Release activity for the input Level.
113        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.
114    @param level
115        A pointer to the Level whose activity is to be released.
116    */
117    void LevelManager::releaseActivity(Level* level)
118    {
119        if (this->levels_.size() > 0)
120        {
121            // If the level is the active level in the front of the list.
122            if (this->levels_.front() == level)
123            {
124                // Deactivate it, remove it from the list and activate the next level in line.
125                level->setActive(false);
126                this->levels_.pop_front();
127                this->activateNextLevel();
128            }
129            else // Else just remove it from the list.
130                this->levels_.erase(std::find(this->levels_.begin(), this->levels_.end(), level));
131        }
132    }
133
134    /**
135    @brief
136        Get the currently active Level.
137    @return
138        Returns a pointer to the currently active level or NULL if there currently are no active Levels.
139    */
140    Level* LevelManager::getActiveLevel()
141    {
142        if (this->levels_.size() > 0)
143            return this->levels_.front();
144        else
145            return 0;
146    }
147
148    /**
149    @brief
150        Activate the next Level.
151    */
152    void LevelManager::activateNextLevel()
153    {
154        if (this->levels_.size() > 0)
155        {
156            // Activate the level that is the first in the list of levels whose activity has been requested.
157            this->levels_.front()->setActive(true);
158            // Make every player enter the newly activated level.
159            for (std::map<unsigned int, PlayerInfo*>::const_iterator it = PlayerManager::getInstance().getClients().begin(); it != PlayerManager::getInstance().getClients().end(); ++it)
160                this->levels_.front()->playerEntered(it->second);
161        }
162    }
163
164    /**
165    @brief
166        Set the default Level.
167    @param levelName
168        The filename of the default Level.
169    */
170    void LevelManager::setDefaultLevel(const std::string& levelName)
171    {
172        ModifyConfigValue(defaultLevelName_, set, levelName);
173    }
174
175    /**
176    @brief
177        Get the number of available Levels.
178        Also updates the list of available Levels.
179    @return
180        Returns the number of available Levels.
181    */
182    unsigned int LevelManager::getNumberOfLevels()
183    {
184        this->updateAvailableLevelList();
185
186        return this->availableLevels_.size();
187    }
188
189    /**
190    @brief
191        Get the LevelInfoItem at the given index in the list of available Levels.
192        The LevelInfoItems are sorted in alphabetical order accoridng to the name of the Level.
193        This method is most efficiently called with consecutive indices (or at least ascending indices).
194    @param index
195        The index of the item that should be returned.
196    @return
197        Returns a pointer to the LevelInfoItem at the given index.
198    */
199    LevelInfoItem* LevelManager::getAvailableLevelListItem(unsigned int index)
200    {
201        if(index >= this->availableLevels_.size())
202            return NULL;
203
204        // If this index directly follows the last we can optimize a lot.
205        if(index == this->nextIndex_)
206        {
207            this->nextIndex_++;
208            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
209            this->nextLevel_++;
210            return *it;
211        }
212        else
213        {
214            // If this index is bigger than the last, we can optimize a little.
215            if(index < this->nextIndex_)
216            {
217                this->nextIndex_ = 0;
218                this->nextLevel_ = this->availableLevels_.begin();
219            }
220            while(this->nextIndex_ != index)
221            {
222                this->nextIndex_++;
223                this->nextLevel_++;
224            }
225            this->nextIndex_++;
226            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
227            this->nextLevel_++;
228            return *it;
229        }
230    }
231
232    /**
233    @brief
234        Compile the list of available Levels.
235        Iterates over all *.oxw files, loads the LevelInfo objects in them and from that it creates the LevelInfoItems which are inserted in a list.
236    */
237    void LevelManager::compileAvailableLevelList()
238    {
239        Ogre::StringVectorPtr levels = Resource::findResourceNames("*.oxw");
240        // Iterate over all *.oxw level files.
241        COUT(3) << "Loading LevelInfos..." << std::endl;
242        for (Ogre::StringVector::const_iterator it = levels->begin(); it != levels->end(); ++it)
243        {
244            //TODO: Replace with tag?
245            if (it->find("old/") != 0)
246            {
247                size_t pos = it->find(".oxw");
248
249                // Load the LevelInfo object from the level file.
250                bool infoExists = false;
251                XMLFile file = XMLFile(*it);
252                ClassTreeMask mask = ClassTreeMask();
253                mask.exclude(ClassIdentifier<BaseObject>::getIdentifier());
254                mask.include(ClassIdentifier<LevelInfo>::getIdentifier());
255                Loader::load(&file, mask, false, true);
256                // Iterate over all LevelInfos.
257                for(ObjectList<LevelInfo>::iterator item = ObjectList<LevelInfo>::begin(); item != ObjectList<LevelInfo>::end(); ++item)
258                {
259                    LevelInfoItem* info = item->copy();
260                    if(info->getXMLFilename() == *it) // If the LevelInfo for this level exists we insert it into the list of available levels.
261                    {
262                        this->availableLevels_.insert(info);
263                        infoExists = true;
264                    }
265                }
266                Loader::unload(&file, mask);
267                if(!infoExists) // If the LevelInfo for this level doesn't exist, we create a new one and insert it into the list of available levels.
268                    this->availableLevels_.insert(new LevelInfoItem(it->substr(0, pos), *it));
269            }
270        }
271    }
272
273    /**
274    @brief
275        Update the list of available Levels.
276    */
277    void LevelManager::updateAvailableLevelList(void)
278    {
279        //TODO: Implement some kind of update?
280    }
281}
Note: See TracBrowser for help on using the repository browser.