Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/class/IdentifierManager.cc @ 10479

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

moved config values and all related functions from Game and Core to GameConfig and CoreConfig respectively. this ensures that no framework features are used by Game and Core before Core itself initialized the framework.

  • Property svn:eol-style set to native
File size: 10.9 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/**
30    @file
31    @brief Implementation of the Identifier class.
32*/
33
34#include "IdentifierManager.h"
35
36#include <ostream>
37
38#include "util/StringUtils.h"
39#include "core/Core.h"
40#include "core/config/ConfigValueContainer.h"
41#include "core/XMLPort.h"
42#include "core/object/ClassFactory.h"
43
44namespace orxonox
45{
46    /* static */ IdentifierManager& IdentifierManager::getInstance()
47    {
48        static IdentifierManager instance;
49        return instance;
50    }
51
52    IdentifierManager::IdentifierManager()
53    {
54        this->hierarchyCreatingCounter_s = 0;
55        this->classIDCounter_s = 0;
56        this->recordTraceForIdentifier_ = NULL;
57    }
58
59    /**
60     * Registers the identifier in all maps of the IdentifierManager.
61     */
62    void IdentifierManager::addIdentifier(Identifier* identifier)
63    {
64        orxout(verbose, context::identifier) << "Adding identifier for " << identifier->getName() << " / " << identifier->getTypeInfo().name() << endl;
65
66        this->identifiers_.insert(identifier);
67        this->identifierByString_[identifier->getName()] = identifier;
68        this->identifierByLowercaseString_[getLowercase(identifier->getName())] = identifier;
69        this->identifierByNetworkId_[identifier->getNetworkID()] = identifier;
70    }
71
72    /**
73        @brief Creates the class-hierarchy by creating and destroying one object of each type.
74    */
75    void IdentifierManager::createClassHierarchy()
76    {
77        orxout(internal_status) << "Create class-hierarchy" << endl;
78        this->startCreatingHierarchy();
79
80        std::set<Identifier*> initializedIdentifiers;
81
82        // ensure root context exists before starting to create objects. if the root context is dynamically created while creating the class hierarchy, we
83        // would mistakenly assume the class of the currently created object inherits from Context
84        Context::getRootContext();
85
86        // iterate over all identifiers, create one instance of each class and initialize the identifiers
87        {
88            Context temporaryContext(NULL);
89            for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
90            {
91                Identifier* identifier = (*it);
92
93                orxout(verbose, context::identifier) << "Initialize ClassIdentifier<" << identifier->getName() << ">-Singleton." << endl;
94                // To initialize the identifier, we create a new object and delete it afterwards.
95                if (identifier->hasFactory())
96                {
97                    this->identifierTraceOfNewObject_.clear();
98                    this->recordTraceForIdentifier_ = identifier;
99
100                    Identifiable* temp = identifier->fabricate(&temporaryContext);
101
102                    this->recordTraceForIdentifier_ = NULL;
103
104                    if (temp->getIdentifier() != identifier)
105                        orxout(internal_error) << "Newly created object of type " << identifier->getName() << " has unexpected identifier. Did you forget to use RegisterObject(classname)?" << endl;
106
107                    identifier->initializeParents(this->identifierTraceOfNewObject_[temp]);
108
109                    delete temp;
110                }
111
112                initializedIdentifiers.insert(identifier);
113            }
114
115            size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
116            if (numberOfObjects > 0)
117                orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
118        }
119
120        // finish the initialization of all identifiers
121        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
122        {
123            Identifier* identifier = (*it);
124
125            if (initializedIdentifiers.find(identifier) != initializedIdentifiers.end())
126                identifier->finishInitialization();
127            else
128                orxout(internal_error) << "Identifier was registered late and is not initialized: " << identifier->getName() << " / " << identifier->getTypeInfo().name() << endl;
129        }
130
131        // only check class hierarchy in dev mode because it's an expensive operation and it requires a developer to fix detected problems anyway.
132        if (!Core::exists() || Core::getInstance().getConfig()->inDevMode())
133            this->verifyClassHierarchy();
134
135        this->stopCreatingHierarchy();
136        orxout(internal_status) << "Finished class-hierarchy creation" << endl;
137    }
138
139    /**
140     * Verifies if the class hierarchy is consistent with the RTTI.
141     */
142    void IdentifierManager::verifyClassHierarchy()
143    {
144        Context temporaryContext(NULL);
145        for (std::set<Identifier*>::const_iterator it1 = this->identifiers_.begin(); it1 != this->identifiers_.end(); ++it1)
146        {
147            if (!(*it1)->hasFactory())
148                continue;
149
150            Identifiable* temp = (*it1)->fabricate(&temporaryContext);
151
152            for (std::set<Identifier*>::const_iterator it2 = this->identifiers_.begin(); it2 != this->identifiers_.end(); ++it2)
153            {
154                bool isA_AccordingToRtti = (*it2)->canDynamicCastObjectToIdentifierClass(temp);
155                bool isA_AccordingToClassHierarchy = temp->isA((*it2));
156
157                if (isA_AccordingToRtti != isA_AccordingToClassHierarchy)
158                {
159                    orxout(internal_error) << "Class hierarchy does not match RTTI: Class hierarchy claims that " << (*it1)->getName() <<
160                        (isA_AccordingToClassHierarchy ? " is a " : " is not a ") << (*it2)->getName() << " but RTTI says the opposite." << endl;
161                }
162            }
163
164            delete temp;
165        }
166        orxout(internal_info) << "Class hierarchy matches RTTI" << endl;
167
168        size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
169        if (numberOfObjects > 0)
170            orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
171    }
172
173    /**
174     * @brief Resets all Identifiers.
175     */
176    void IdentifierManager::destroyClassHierarchy()
177    {
178        orxout(internal_status) << "Destroy class-hierarchy" << endl;
179        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
180            (*it)->reset();
181    }
182
183    /**
184     * @brief Notifies the IdentifierManager about a newly created object while creating the class hierarchy.
185     */
186    void IdentifierManager::createdObject(Identifiable* identifiable)
187    {
188        if (this->isCreatingHierarchy())
189        {
190            if (this->recordTraceForIdentifier_)
191            {
192                std::list<const Identifier*>& traceForObject = this->identifierTraceOfNewObject_[identifiable];
193                if (std::find(traceForObject.begin(), traceForObject.end(), identifiable->getIdentifier()) != traceForObject.end())
194                {
195                    orxout(internal_warning) << this->recordTraceForIdentifier_->getName() << " inherits two times from " <<
196                        identifiable->getIdentifier()->getName() << ". Did you forget to use virtual inheritance?" << endl;
197                }
198                traceForObject.push_back(identifiable->getIdentifier());
199            }
200        }
201        else
202            orxout(internal_warning) << "createdObject() called outside of class hierarchy creation" << endl;
203    }
204
205    /**
206        @brief Returns the Identifier with a given name.
207        @param name The name of the wanted Identifier
208        @return The Identifier
209    */
210    Identifier* IdentifierManager::getIdentifierByString(const std::string& name)
211    {
212        std::map<std::string, Identifier*>::const_iterator it = this->identifierByString_.find(name);
213        if (it != this->identifierByString_.end())
214            return it->second;
215        else
216            return 0;
217    }
218
219    /**
220        @brief Returns the Identifier with a given name in lowercase.
221        @param name The name of the wanted Identifier
222        @return The Identifier
223    */
224    Identifier* IdentifierManager::getIdentifierByLowercaseString(const std::string& name)
225    {
226        std::map<std::string, Identifier*>::const_iterator it = this->identifierByLowercaseString_.find(name);
227        if (it != this->identifierByLowercaseString_.end())
228            return it->second;
229        else
230            return 0;
231    }
232
233    /**
234        @brief Returns the Identifier with a given network ID.
235        @param id The network ID of the wanted Identifier
236        @return The Identifier
237    */
238    Identifier* IdentifierManager::getIdentifierByID(const uint32_t id)
239    {
240        std::map<uint32_t, Identifier*>::const_iterator it = this->identifierByNetworkId_.find(id);
241        if (it != this->identifierByNetworkId_.end())
242            return it->second;
243        else
244            return 0;
245    }
246
247    /**
248        @brief Returns the Identifier with a given typeid-name.
249        @param name The typeid-name of the wanted Identifier
250        @return The Identifier
251    */
252    Identifier* IdentifierManager::getIdentifierByTypeInfo(const std::type_info& typeInfo)
253    {
254        // TODO: use std::type_index and a map to find identifiers by type_info (only with c++11)
255        for (std::set<Identifier*>::iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
256            if ((*it)->getTypeInfo() == typeInfo)
257                return (*it);
258        return 0;
259    }
260
261    /**
262        @brief Cleans the NetworkID map (needed on clients for correct initialization)
263    */
264    void IdentifierManager::clearNetworkIDs()
265    {
266        this->identifierByNetworkId_.clear();
267    }
268
269    /**
270        @brief Destroys all Identifiers. Called when exiting the program.
271    */
272    void IdentifierManager::destroyAllIdentifiers()
273    {
274        for (std::set<Identifier*>::iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
275            delete (*it);
276
277        this->identifiers_.clear();
278        this->identifierByString_.clear();
279        this->identifierByLowercaseString_.clear();
280        this->identifierByNetworkId_.clear();
281    }
282}
Note: See TracBrowser for help on using the repository browser.