Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/orxonox/Level.cc @ 11016

Last change on this file since 11016 was 10916, checked in by landauf, 10 years ago

use actual types instead of 'auto'. only exception is for complicated template types, e.g. when iterating over a map

  • Property svn:eol-style set to native
File size: 7.8 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 *      ...
26 *
27 */
28
29#include "Level.h"
30
31#include "util/Math.h"
32#include "util/SubString.h"
33#include "core/CoreIncludes.h"
34#include "core/Loader.h"
35#include "core/Template.h"
36#include "core/XMLFile.h"
37#include "core/XMLPort.h"
38#include "core/module/PluginReference.h"
39
40#include "infos/PlayerInfo.h"
41#include "gametypes/Gametype.h"
42#include "overlays/OverlayGroup.h"
43#include "LevelManager.h"
44
45namespace orxonox
46{
47    RegisterClass(Level);
48
49    Level::Level(Context* context) : BaseObject(context), Synchronisable(context), Context(context)
50    {
51        RegisterObject(Level);
52
53        this->setLevel(WeakPtr<Level>(this)); // store a weak-pointer to itself (a strong-pointer would create a recursive dependency)
54
55        this->registerVariables();
56        this->xmlfilename_ = this->getFilename();
57        this->xmlfile_ = nullptr;
58    }
59
60    Level::~Level()
61    {
62        if (this->isInitialized())
63        {
64            if (LevelManager::exists())
65                LevelManager::getInstance().releaseActivity(this);
66
67            if (this->xmlfile_)
68                Loader::getInstance().unload(this->xmlfile_);
69
70            this->unloadPlugins();
71        }
72    }
73
74    void Level::XMLPort(Element& xmlelement, XMLPort::Mode mode)
75    {
76        SUPER(Level, XMLPort, xmlelement, mode);
77
78        XMLPortParam(Level, "plugins",  setPluginsString,  getPluginsString,  xmlelement, mode);
79        XMLPortParam(Level, "gametype", setGametypeString, getGametypeString, xmlelement, mode).defaultValues("Gametype");
80
81        XMLPortObject(Level, MeshLodInformation, "lodinformation", addLodInfo, getLodInfo, xmlelement, mode);
82        XMLPortObjectExtended(Level, BaseObject, "", addObject, getObject, xmlelement, mode, true, false);
83    }
84
85    void Level::registerVariables()
86    {
87        registerVariable(this->xmlfilename_,            VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::networkcallback_applyXMLFile));
88        registerVariable(this->name_,                   VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::changedName));
89        registerVariable(this->networkTemplateNames_,   VariableDirection::ToClient, new NetworkCallback<Level>(this, &Level::networkCallbackTemplatesChanged));
90    }
91
92    void Level::networkcallback_applyXMLFile()
93    {
94        orxout(user_status) << "Loading level \"" << this->xmlfilename_ << "\"..." << endl;
95
96        ClassTreeMask mask;
97        mask.exclude(Class(BaseObject));
98        mask.include(Class(Template));
99        mask.include(Class(OverlayGroup)); // HACK to include the ChatOverlay
100
101        this->xmlfile_ = new XMLFile(mask, this->xmlfilename_);
102
103        Loader::getInstance().load(this->xmlfile_);
104    }
105
106    void Level::networkCallbackTemplatesChanged()
107    {
108        for(const std::string& name : this->networkTemplateNames_)
109        {
110            assert(Template::getTemplate(name));
111            Template::getTemplate(name)->applyOn(this);
112        }
113    }
114
115    void Level::setPluginsString(const std::string& pluginsString)
116    {
117        // unload old plugins
118        this->unloadPlugins();
119
120        // load new plugins
121        this->pluginsString_ = pluginsString;
122        SubString tokens(pluginsString, ",");
123        for (size_t i = 0; i < tokens.size(); ++i)
124            this->plugins_.push_back(new PluginReference(tokens[i]));
125    }
126
127    void Level::unloadPlugins()
128    {
129        // use destroyLater() - this ensures that plugins are not unloaded too early.
130        // Note: When a level gets unloaded, the Level object is usually the last object that gets destroyed. This is because all other
131        //       objects inside a level have a StrongPtr (in BaseObject) that references the Level object. This means that the Level
132        //       object is only destroyed, when all StrongPtrs that pointed to it were destroyed. But at the time when the last StrongPtr
133        //       is destroyed, the other object is not yet fully destroyed because the StrongPtr is destroyed in ~BaseObject (and this
134        //       means that e.g. ~Identifiable was not yet called for this object). This means that technically there are still other
135        //       objects alive when ~Level is called. This is the reason why we cannot directly destroy() the Plugins - instead we need
136        //       to call destroyLater() to ensure that no instances from this plugin exist anymore.
137        for (PluginReference* plugin : this->plugins_)
138            plugin->destroyLater();
139        this->plugins_.clear();
140    }
141
142    void Level::setGametypeString(const std::string& gametype)
143    {
144        Identifier* identifier = ClassByString(gametype);
145
146        if (!identifier || !identifier->isA(Class(Gametype)))
147        {
148            orxout(internal_error) << "\"" << gametype << "\" is not a valid gametype." << endl;
149            identifier = Class(Gametype);
150            this->gametype_ = "Gametype";
151        }
152        else
153            this->gametype_ = gametype;
154
155        Gametype* rootgametype = orxonox_cast<Gametype*>(identifier->fabricate(this));
156
157        // store a weak-pointer to the gametype to avoid a circular dependency between this level and the gametype (which has a strong-reference on this level)
158        this->setGametype(WeakPtr<Gametype>(rootgametype));
159
160        rootgametype->init(); // call init() AFTER the gametype was set
161
162        if (LevelManager::exists())
163            LevelManager::getInstance().requestActivity(this);
164    }
165
166
167    void Level::addObject(BaseObject* object)
168    {
169        this->objects_.push_back(object);
170    }
171
172    BaseObject* Level::getObject(unsigned int index) const
173    {
174        unsigned int i = 0;
175        for (BaseObject* object : this->objects_)
176        {
177            if (i == index)
178                return object;
179            ++i;
180        }
181        return nullptr;
182    }
183
184    void Level::addLodInfo(MeshLodInformation* lodInformation)
185    {
186        std::string meshName = lodInformation->getMeshName();
187//         this->lodInformation_.insert(std::make_pair(meshName,lodInformation));
188        if( this->lodInformation_.find(meshName) != this->lodInformation_.end())
189            orxout(verbose, context::lod) << "replacing lod information for " << meshName << endl;
190        this->lodInformation_[meshName] = lodInformation;
191    }
192
193    MeshLodInformation* Level::getLodInfo(std::string meshName) const
194    {
195        if(this->lodInformation_.find(meshName)!=this->lodInformation_.end())
196            return this->lodInformation_.find(meshName)->second;
197
198        return nullptr;
199    }
200
201    void Level::playerEntered(PlayerInfo* player)
202    {
203        orxout(internal_info) << "player entered level (id: " << player->getClientID() << ", name: " << player->getName() << ')' << endl;
204        player->switchGametype(this->getGametype());
205    }
206
207    void Level::playerLeft(PlayerInfo* player)
208    {
209        orxout(internal_info) << "player left level (id: " << player->getClientID() << ", name: " << player->getName() << ')' << endl;
210        player->switchGametype(nullptr);
211    }
212}
Note: See TracBrowser for help on using the repository browser.