Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Oct 4, 2015, 9:12:21 PM (9 years ago)
Author:
landauf
Message:

merged branch core7 back to trunk

Location:
code/trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/libraries/core/class/Identifiable.cc

    r9667 r10624  
    4141namespace orxonox
    4242{
    43     RegisterClassNoArgs(Identifiable);
     43    RegisterClassNoArgs(Identifiable).virtualBase();
    4444
    4545    /**
  • code/trunk/src/libraries/core/class/Identifier.cc

    r9667 r10624  
    4444namespace orxonox
    4545{
     46    bool Identifier::initConfigValues_s = true;
     47
    4648    // ###############################
    4749    // ###       Identifier        ###
     
    5052        @brief Constructor: No factory, no object created, new ObjectList and a unique networkID.
    5153    */
    52     Identifier::Identifier()
    53         : classID_(IdentifierManager::getInstance().getUniqueClassId())
    54     {
    55         this->factory_ = 0;
     54    Identifier::Identifier(const std::string& name, Factory* factory, bool bLoadable)
     55    {
     56        orxout(verbose, context::identifier) << "Create identifier for " << name << endl;
     57
     58        static unsigned int classIDCounter = 0;
     59
     60        this->classID_ = classIDCounter++;
     61        this->name_ = name;
     62        this->factory_ = factory;
     63        this->bLoadable_ = bLoadable;
    5664        this->bInitialized_ = false;
    57         this->bLoadable_ = false;
     65        this->bIsVirtualBase_ = false;
    5866
    5967        this->bHasConfigValues_ = false;
     
    7179            delete this->factory_;
    7280
     81        for (std::list<const InheritsFrom*>::const_iterator it = this->manualDirectParents_.begin(); it != this->manualDirectParents_.end(); ++it)
     82            delete (*it);
     83
     84        // erase this Identifier from all related identifiers
     85        for (std::list<const Identifier*>::const_iterator it = this->parents_.begin(); it != this->parents_.end(); ++it)
     86            const_cast<Identifier*>(*it)->children_.erase(this);
     87        for (std::list<const Identifier*>::const_iterator it = this->directParents_.begin(); it != this->directParents_.end(); ++it)
     88            const_cast<Identifier*>(*it)->directChildren_.erase(this);
     89        for (std::set<const Identifier*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
     90            const_cast<Identifier*>(*it)->parents_.remove(this);
     91        for (std::set<const Identifier*>::const_iterator it = this->directChildren_.begin(); it != this->directChildren_.end(); ++it)
     92            const_cast<Identifier*>(*it)->directParents_.remove(this);
     93
    7394        for (std::map<std::string, ConfigValueContainer*>::iterator it = this->configValues_.begin(); it != this->configValues_.end(); ++it)
    7495            delete (it->second);
     
    7798        for (std::map<std::string, XMLPortObjectContainer*>::iterator it = this->xmlportObjectContainers_.begin(); it != this->xmlportObjectContainers_.end(); ++it)
    7899            delete (it->second);
    79     }
    80 
    81     /**
    82         @brief Sets the name of the class.
    83     */
    84     void Identifier::setName(const std::string& name)
    85     {
    86         if (name != this->name_)
    87         {
    88             this->name_ = name;
    89             IdentifierManager::getInstance().addIdentifierToLookupMaps(this);
    90         }
    91     }
    92 
    93     void Identifier::setFactory(Factory* factory)
    94     {
    95         if (this->factory_)
    96             delete this->factory_;
    97 
    98         this->factory_ = factory;
    99100    }
    100101
     
    126127    {
    127128        this->networkID_ = id;
    128         IdentifierManager::getInstance().addIdentifierToLookupMaps(this);
     129        IdentifierManager::getInstance().addIdentifier(this);    // add with new id
    129130    }
    130131
     
    132133     * @brief Used to define the direct parents of an Identifier of an abstract class.
    133134     */
    134     Identifier& Identifier::inheritsFrom(Identifier* directParent)
    135     {
    136         if (this->parents_.empty())
    137             this->directParents_.insert(directParent);
    138         else
    139             orxout(internal_error) << "Trying to add " << directParent->getName() << " as a direct parent of " << this->getName() << " after the latter was already initialized" << endl;
     135    Identifier& Identifier::inheritsFrom(InheritsFrom* directParent)
     136    {
     137        if (this->directParents_.empty())
     138            this->manualDirectParents_.push_back(directParent);
     139        else
     140            orxout(internal_error) << "Trying to manually add direct parent of " << this->getName() << " after the latter was already initialized" << endl;
    140141
    141142        return *this;
     
    144145    /**
    145146     * @brief Initializes the parents of this Identifier while creating the class hierarchy.
    146      * @param identifiers All identifiers that were used to create an instance of this class (including this identifier itself)
    147      */
    148     void Identifier::initializeParents(const std::set<const Identifier*>& identifiers)
     147     * @param initializationTrace All identifiers that were recorded while creating an instance of this class (including nested classes and this identifier itself)
     148     */
     149    void Identifier::initializeParents(const std::list<const Identifier*>& initializationTrace)
    149150    {
    150151        if (!IdentifierManager::getInstance().isCreatingHierarchy())
     
    154155        }
    155156
    156         for (std::set<const Identifier*>::const_iterator it = identifiers.begin(); it != identifiers.end(); ++it)
    157             if (*it != this)
    158                 this->parents_.insert(*it);
    159     }
    160 
    161     /**
    162      * @brief Initializes the direct parents of this Identifier while creating the class hierarchy. This is only intended for abstract classes.
    163      */
    164     void Identifier::initializeDirectParentsOfAbstractClass()
     157        if (this->directParents_.empty())
     158        {
     159            for (std::list<const Identifier*>::const_iterator it = initializationTrace.begin(); it != initializationTrace.end(); ++it)
     160                if (*it != this)
     161                    this->parents_.push_back(*it);
     162        }
     163        else
     164            orxout(internal_error) << "Trying to add parents to " << this->getName() << " after it was already initialized with manual calls to inheritsFrom<Class>()." << endl;
     165    }
     166
     167    /**
     168     * @brief Finishes the initialization of this Identifier after creating the class hierarchy by wiring the (direct) parent/child references correctly.
     169     */
     170    void Identifier::finishInitialization()
    165171    {
    166172        if (!IdentifierManager::getInstance().isCreatingHierarchy())
    167173        {
    168             orxout(internal_warning) << "Identifier::initializeDirectParentsOfAbstractClass() created outside of class hierarchy creation" << endl;
     174            orxout(internal_warning) << "Identifier::finishInitialization() created outside of class hierarchy creation" << endl;
    169175            return;
    170176        }
    171177
    172         // only Identifiable is allowed to have no parents (even tough it's currently not abstract)
    173         if (this->directParents_.empty() && !this->isExactlyA(Class(Identifiable)))
    174         {
    175             orxout(internal_error) << "Identifier " << this->getName() << " / " << this->getTypeidName() << " is marked as abstract but has no direct parents defined" << endl;
     178        if (this->isInitialized())
     179            return;
     180
     181        if (!this->parents_.empty())
     182        {
     183            // parents defined -> this class was initialized by creating a sample instance and recording the trace of identifiers
     184
     185            // initialize all parents
     186            for (std::list<const Identifier*>::const_iterator it = this->parents_.begin(); it != this->parents_.end(); ++it)
     187                const_cast<Identifier*>(*it)->finishInitialization(); // initialize parent
     188
     189            // parents of parents are no direct parents of this identifier
     190            this->directParents_ = this->parents_;
     191            for (std::list<const Identifier*>::const_iterator it_parent = this->parents_.begin(); it_parent != this->parents_.end(); ++it_parent)
     192                for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
     193                    this->directParents_.remove(*it_parent_parent);
     194
     195            this->verifyIdentifierTrace();
     196        }
     197        else if (!this->manualDirectParents_.empty())
     198        {
     199            // no parents defined -> this class was manually initialized by calling inheritsFrom<Class>()
     200
     201            // initialize all direct parents
     202            for (std::list<const InheritsFrom*>::const_iterator it = this->manualDirectParents_.begin(); it != this->manualDirectParents_.end(); ++it)
     203            {
     204                Identifier* directParent = (*it)->getParent();
     205                this->directParents_.push_back(directParent);
     206                directParent->finishInitialization(); // initialize parent
     207            }
     208
     209            // direct parents and their parents are also parents of this identifier (but only add them once)
     210            for (std::list<const Identifier*>::const_iterator it_parent = this->directParents_.begin(); it_parent != this->directParents_.end(); ++it_parent)
     211            {
     212                for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
     213                    this->addIfNotExists(this->parents_, *it_parent_parent);
     214                this->addIfNotExists(this->parents_, *it_parent);
     215            }
     216        }
     217        else if (!this->isExactlyA(Class(Identifiable)))
     218        {
     219            // only Identifiable is allowed to have no parents (even tough it's currently not abstract)
     220            orxout(internal_error) << "Identifier " << this->getName() << " / " << this->getTypeInfo().name() << " is marked as abstract but has no direct parents defined" << endl;
    176221            orxout(internal_error) << "  If this class is not abstract, use RegisterClass(ThisClass);" << endl;
    177222            orxout(internal_error) << "  If this class is abstract, use RegisterAbstractClass(ThisClass).inheritsFrom(Class(BaseClass));" << endl;
    178223        }
    179     }
    180 
    181     /**
    182      * @brief Finishes the initialization of this Identifier after creating the class hierarchy by wiring the (direct) parent/child references correctly.
    183      */
    184     void Identifier::finishInitialization()
    185     {
    186         if (!IdentifierManager::getInstance().isCreatingHierarchy())
    187         {
    188             orxout(internal_warning) << "Identifier::finishInitialization() created outside of class hierarchy creation" << endl;
    189             return;
    190         }
    191 
    192         if (this->isInitialized())
    193             return;
    194 
    195         // if no direct parents were defined, initialize them with the set of all parents
    196         if (this->directParents_.empty())
    197             this->directParents_ = this->parents_;
    198 
    199         // initialize all parents before continuing to initialize this identifier
    200         for (std::set<const Identifier*>::const_iterator it = this->directParents_.begin(); it != this->directParents_.end(); ++it)
    201         {
    202             Identifier* directParent = const_cast<Identifier*>(*it);
    203             directParent->finishInitialization(); // initialize parent
    204             this->parents_.insert(directParent);  // direct parent is also a parent
    205             this->parents_.insert(directParent->parents_.begin(), directParent->parents_.end()); // parents of direct parent are also parents
    206         }
    207 
    208         // parents of parents are no direct parents of this identifier
    209         for (std::set<const Identifier*>::const_iterator it_parent = this->parents_.begin(); it_parent != this->parents_.end(); ++it_parent)
    210             for (std::set<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
    211                 this->directParents_.erase(*it_parent_parent);
    212224
    213225        // tell all parents that this identifier is a child
    214         for (std::set<const Identifier*>::const_iterator it = this->parents_.begin(); it != this->parents_.end(); ++it)
     226        for (std::list<const Identifier*>::const_iterator it = this->parents_.begin(); it != this->parents_.end(); ++it)
    215227            const_cast<Identifier*>(*it)->children_.insert(this);
    216228
    217229        // tell all direct parents that this identifier is a direct child
    218         for (std::set<const Identifier*>::const_iterator it = this->directParents_.begin(); it != this->directParents_.end(); ++it)
     230        for (std::list<const Identifier*>::const_iterator it = this->directParents_.begin(); it != this->directParents_.end(); ++it)
    219231        {
    220232            const_cast<Identifier*>(*it)->directChildren_.insert(this);
     
    228240
    229241    /**
     242     * Resets all information about the class hierarchy. The identifier is considered uninitialized afterwards.
     243     */
     244    void Identifier::reset()
     245    {
     246        this->directParents_.clear();
     247        this->parents_.clear();
     248        this->directChildren_.clear();
     249        this->children_.clear();
     250        this->bInitialized_ = false;
     251    }
     252
     253    /**
     254     * Verifies if the recorded trace of parent identifiers matches the expected trace according to the class hierarchy. If it doesn't match, the class
     255     * hierarchy is likely wrong, e.g. due to wrong inheritsFrom<>() definitions in abstract classes.
     256     */
     257    void Identifier::verifyIdentifierTrace() const
     258    {
     259
     260        std::list<const Identifier*> expectedIdentifierTrace;
     261
     262        // if any parent class is virtual, it will be instantiated first, so we need to add them first.
     263        for (std::list<const Identifier*>::const_iterator it_parent = this->parents_.begin(); it_parent != this->parents_.end(); ++it_parent)
     264        {
     265            if ((*it_parent)->isVirtualBase())
     266            {
     267                for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
     268                    this->addIfNotExists(expectedIdentifierTrace, *it_parent_parent);
     269                this->addIfNotExists(expectedIdentifierTrace, *it_parent);
     270            }
     271        }
     272
     273        // now all direct parents get created recursively. already added identifiers (e.g. virtual base classes) are not added again.
     274        for (std::list<const Identifier*>::const_iterator it_parent = this->directParents_.begin(); it_parent != this->directParents_.end(); ++it_parent)
     275        {
     276            for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
     277                this->addIfNotExists(expectedIdentifierTrace, *it_parent_parent);
     278            this->addIfNotExists(expectedIdentifierTrace, *it_parent);
     279        }
     280
     281        // check if the expected trace matches the actual trace (which was defined by creating a sample instance)
     282        if (expectedIdentifierTrace != this->parents_)
     283        {
     284            orxout(internal_warning) << this->getName() << " has an unexpected initialization trace:" << endl;
     285
     286            orxout(internal_warning) << "  Actual trace (after creating a sample instance):" << endl << "    ";
     287            for (std::list<const Identifier*>::const_iterator it_parent = this->parents_.begin(); it_parent != this->parents_.end(); ++it_parent)
     288                orxout(internal_warning) << " " << (*it_parent)->getName();
     289            orxout(internal_warning) << endl;
     290
     291            orxout(internal_warning) << "  Expected trace (according to class hierarchy definitions):" << endl << "    ";
     292            for (std::list<const Identifier*>::const_iterator it_parent = expectedIdentifierTrace.begin(); it_parent != expectedIdentifierTrace.end(); ++it_parent)
     293                orxout(internal_warning) << " " << (*it_parent)->getName();
     294            orxout(internal_warning) << endl;
     295
     296            orxout(internal_warning) << "  Direct parents (according to class hierarchy definitions):" << endl << "    ";
     297            for (std::list<const Identifier*>::const_iterator it_parent = this->directParents_.begin(); it_parent != this->directParents_.end(); ++it_parent)
     298                orxout(internal_warning) << " " << (*it_parent)->getName();
     299            orxout(internal_warning) << endl;
     300        }
     301    }
     302
     303    /**
     304     * Adds @param identifierToAdd to @param list if this identifier is not already contained in the list.
     305     */
     306    void Identifier::addIfNotExists(std::list<const Identifier*>& list, const Identifier* identifierToAdd) const
     307    {
     308        if (std::find(list.begin(), list.end(), identifierToAdd) == list.end())
     309            list.push_back(identifierToAdd);
     310    }
     311
     312    /**
    230313        @brief Returns true, if the Identifier is at least of the given type.
    231314        @param identifier The identifier to compare with
     
    233316    bool Identifier::isA(const Identifier* identifier) const
    234317    {
    235         return (identifier == this || (this->parents_.find(identifier) != this->parents_.end()));
     318        return (identifier == this || (this->isChildOf(identifier)));
    236319    }
    237320
     
    251334    bool Identifier::isChildOf(const Identifier* identifier) const
    252335    {
    253         return (this->parents_.find(identifier) != this->parents_.end());
     336        return (std::find(this->parents_.begin(), this->parents_.end(),  identifier) != this->parents_.end());
    254337    }
    255338
     
    260343    bool Identifier::isDirectChildOf(const Identifier* identifier) const
    261344    {
    262         return (this->directParents_.find(identifier) != this->directParents_.end());
     345        return (std::find(this->directParents_.begin(), this->directParents_.end(), identifier) != this->directParents_.end());
    263346    }
    264347
  • code/trunk/src/libraries/core/class/Identifier.h

    r9667 r10624  
    8080#include <typeinfo>
    8181#include <loki/TypeTraits.h>
     82#include <boost/static_assert.hpp>
     83#include <boost/type_traits/is_base_of.hpp>
    8284
    8385#include "util/Output.h"
     86#include "util/OrxAssert.h"
    8487#include "core/object/ObjectList.h"
    8588#include "core/object/Listable.h"
     
    109112    {
    110113        public:
    111             Identifier();
     114            struct InheritsFrom //! helper class to manually define inheritance
     115            {
     116                virtual ~InheritsFrom() {}
     117                virtual Identifier* getParent() const = 0;
     118            };
     119
     120        public:
     121            Identifier(const std::string& name, Factory* factory, bool bLoadable);
    112122            Identifier(const Identifier& identifier); // don't copy
    113123            virtual ~Identifier();
     
    115125            /// Returns the name of the class the Identifier belongs to.
    116126            inline const std::string& getName() const { return this->name_; }
    117             void setName(const std::string& name);
    118 
    119             /// Returns the name of the class as it is returned by typeid(T).name()
    120             virtual const std::string& getTypeidName() = 0;
     127
     128            /// Returns the type_info of the class as it is returned by typeid(T)
     129            virtual const std::type_info& getTypeInfo() = 0;
    121130
    122131            /// Returns the network ID to identify a class through the network.
     
    127136            ORX_FORCEINLINE unsigned int getClassID() const { return this->classID_; }
    128137
    129             /// Sets the Factory.
    130             void setFactory(Factory* factory);
    131138            /// Returns true if the Identifier has a Factory.
    132139            inline bool hasFactory() const { return (this->factory_ != 0); }
     
    136143            /// Returns true if the class can be loaded through XML.
    137144            inline bool isLoadable() const { return this->bLoadable_; }
    138             /// Set the class to be loadable through XML or not.
    139             inline void setLoadable(bool bLoadable) { this->bLoadable_ = bLoadable; }
     145
     146            /// Returns true if child classes should inherit virtually from this class.
     147            inline bool isVirtualBase() const { return this->bIsVirtualBase_; }
     148            /// Defines if child classes should inherit virtually from this class.
     149            inline void setVirtualBase(bool bIsVirtualBase) { this->bIsVirtualBase_ = bIsVirtualBase; }
    140150
    141151            /// Returns true if the Identifier was completely initialized.
    142152            inline bool isInitialized() const { return this->bInitialized_; }
     153
     154            virtual void destroyObjects() = 0;
     155
     156            virtual bool canDynamicCastObjectToIdentifierClass(Identifiable* object) const = 0;
     157
     158            static bool initConfigValues_s; // TODO: this is a hack - remove it as soon as possible
    143159
    144160
     
    146162            ////// Class Hierarchy //////
    147163            /////////////////////////////
    148             Identifier& inheritsFrom(Identifier* directParent);
    149 
    150             void initializeParents(const std::set<const Identifier*>& identifiers);
    151             void initializeDirectParentsOfAbstractClass();
     164            Identifier& inheritsFrom(InheritsFrom* directParent);
     165
     166            void initializeParents(const std::list<const Identifier*>& initializationTrace);
    152167            void finishInitialization();
     168            void reset();
    153169
    154170            bool isA(const Identifier* identifier) const;
     
    159175            bool isDirectParentOf(const Identifier* identifier) const;
    160176
     177            /// Returns the direct parents of the class the Identifier belongs to.
     178            inline const std::list<const Identifier*>& getDirectParents() const { return this->directParents_; }
    161179            /// Returns the parents of the class the Identifier belongs to.
    162             inline const std::set<const Identifier*>& getParents() const { return this->parents_; }
    163             /// Returns the begin-iterator of the parents-list.
    164             inline std::set<const Identifier*>::const_iterator getParentsBegin() const { return this->parents_.begin(); }
    165             /// Returns the end-iterator of the parents-list.
    166             inline std::set<const Identifier*>::const_iterator getParentsEnd() const { return this->parents_.end(); }
    167 
     180            inline const std::list<const Identifier*>& getParents() const { return this->parents_; }
     181
     182            /// Returns the direct children the class the Identifier belongs to.
     183            inline const std::set<const Identifier*>& getDirectChildren() const { return this->directChildren_; }
    168184            /// Returns the children of the class the Identifier belongs to.
    169185            inline const std::set<const Identifier*>& getChildren() const { return this->children_; }
    170             /// Returns the begin-iterator of the children-list.
    171             inline std::set<const Identifier*>::const_iterator getChildrenBegin() const { return this->children_.begin(); }
    172             /// Returns the end-iterator of the children-list.
    173             inline std::set<const Identifier*>::const_iterator getChildrenEnd() const { return this->children_.end(); }
    174 
    175             /// Returns the direct parents of the class the Identifier belongs to.
    176             inline const std::set<const Identifier*>& getDirectParents() const { return this->directParents_; }
    177             /// Returns the begin-iterator of the direct-parents-list.
    178             inline std::set<const Identifier*>::const_iterator getDirectParentsBegin() const { return this->directParents_.begin(); }
    179             /// Returns the end-iterator of the direct-parents-list.
    180             inline std::set<const Identifier*>::const_iterator getDirectParentsEnd() const { return this->directParents_.end(); }
    181 
    182             /// Returns the direct children the class the Identifier belongs to.
    183             inline const std::set<const Identifier*>& getDirectChildren() const { return this->directChildren_; }
    184             /// Returns the begin-iterator of the direct-children-list.
    185             inline std::set<const Identifier*>::const_iterator getDirectChildrenBegin() const { return this->directChildren_.begin(); }
    186             /// Returns the end-iterator of the direct-children-list.
    187             inline std::set<const Identifier*>::const_iterator getDirectChildrenEnd() const { return this->directChildren_.end(); }
    188186
    189187
     
    223221            XMLPortObjectContainer* getXMLPortObjectContainer(const std::string& sectionname);
    224222
    225 
    226223        protected:
    227224            virtual void createSuperFunctionCaller() const = 0;
    228225
    229226        private:
    230             std::set<const Identifier*> parents_;                          //!< The parents of the class the Identifier belongs to
     227            void verifyIdentifierTrace() const;
     228            void addIfNotExists(std::list<const Identifier*>& list, const Identifier* identifierToAdd) const;
     229
     230            std::list<const InheritsFrom*> manualDirectParents_;            //!< Manually defined direct parents
     231            std::list<const Identifier*> directParents_;                    //!< The direct parents of the class the Identifier belongs to (sorted by their order of initialization)
     232            std::list<const Identifier*> parents_;                          //!< The parents of the class the Identifier belongs to (sorted by their order of initialization)
     233
     234            std::set<const Identifier*> directChildren_;                   //!< The direct children of the class the Identifier belongs to
    231235            std::set<const Identifier*> children_;                         //!< The children of the class the Identifier belongs to
    232 
    233             std::set<const Identifier*> directParents_;                    //!< The direct parents of the class the Identifier belongs to
    234             std::set<const Identifier*> directChildren_;                   //!< The direct children of the class the Identifier belongs to
    235236
    236237            bool bInitialized_;                                            //!< Is true if the Identifier was completely initialized
    237238            bool bLoadable_;                                               //!< False = it's not permitted to load the object through XML
     239            bool bIsVirtualBase_;                                          //!< If true, it is recommended to inherit virtually from this class. This changes the order of initialization of child classes, thus this information is necessary to check the class hierarchy.
    238240            std::string name_;                                             //!< The name of the class the Identifier belongs to
    239241            Factory* factory_;                                             //!< The Factory, able to create new objects of the given class (if available)
    240242            uint32_t networkID_;                                           //!< The network ID to identify a class through the network
    241             const unsigned int classID_;                                   //!< Uniquely identifies a class (might not be the same as the networkID_)
     243            unsigned int classID_;                                         //!< Uniquely identifies a class (might not be the same as the networkID_)
    242244
    243245            bool bHasConfigValues_;                                        //!< True if this class has at least one assigned config value
     
    267269    class ClassIdentifier : public Identifier
    268270    {
     271        BOOST_STATIC_ASSERT((boost::is_base_of<Identifiable, T>::value));
     272
    269273        #ifndef DOXYGEN_SHOULD_SKIP_THIS
    270274          #define SUPER_INTRUSIVE_DECLARATION_INCLUDE
     
    273277
    274278        public:
    275             static ClassIdentifier<T>* getIdentifier();
    276             static ClassIdentifier<T>* getIdentifier(const std::string& name);
    277 
    278             bool initializeObject(T* object);
    279 
    280             void setConfigValues(T* object, Configurable*) const;
    281             void setConfigValues(T* object, Identifiable*) const;
    282 
    283             void addObjectToList(T* object, Listable*);
    284             void addObjectToList(T* object, Identifiable*);
    285 
    286             virtual void updateConfigValues(bool updateChildren = true) const;
    287 
    288             virtual const std::string& getTypeidName()
    289                 { return this->typeidName_; }
    290 
    291         private:
    292             static void initializeIdentifier();
    293 
    294             ClassIdentifier(const ClassIdentifier<T>& identifier) {}    // don't copy
    295             ClassIdentifier()
     279            ClassIdentifier(const std::string& name, Factory* factory, bool bLoadable) : Identifier(name, factory, bLoadable)
    296280            {
    297                 this->typeidName_ = typeid(T).name();
     281                OrxVerify(ClassIdentifier<T>::classIdentifier_s == NULL, "Assertion failed in ClassIdentifier of type " << typeid(T).name());
     282                ClassIdentifier<T>::classIdentifier_s = this;
     283
    298284                SuperFunctionInitialization<0, T>::initialize(this);
    299285            }
     
    303289            }
    304290
     291            bool initializeObject(T* object);
     292
     293            virtual void updateConfigValues(bool updateChildren = true) const;
     294
     295            virtual const std::type_info& getTypeInfo()
     296                { return typeid(T); }
     297
     298            virtual bool canDynamicCastObjectToIdentifierClass(Identifiable* object) const
     299                { return dynamic_cast<T*>(object) != 0; }
     300
     301            virtual void destroyObjects();
     302
     303            static ClassIdentifier<T>* getIdentifier();
     304
     305        private:
     306            ClassIdentifier(const ClassIdentifier<T>& identifier) {}    // don't copy
     307
     308            void setConfigValues(T* object, Configurable*) const;
     309            void setConfigValues(T* object, Identifiable*) const;
     310
     311            void addObjectToList(T* object, Listable*);
     312            void addObjectToList(T* object, Identifiable*);
     313
     314            void destroyObjects(Listable*);
     315            void destroyObjects(void*);
     316
     317            void destroyObject(Destroyable* object);
     318            void destroyObject(void* object);
     319
    305320            void updateConfigValues(bool updateChildren, Listable*) const;
    306321            void updateConfigValues(bool updateChildren, Identifiable*) const;
    307322
    308             std::string typeidName_;
    309323            static WeakPtr<ClassIdentifier<T> > classIdentifier_s;
    310324    };
     
    318332    */
    319333    template <class T>
    320     inline ClassIdentifier<T>* ClassIdentifier<T>::getIdentifier()
    321     {
    322         // check if the Identifier already exists
    323         if (!ClassIdentifier<T>::classIdentifier_s)
    324             ClassIdentifier<T>::initializeIdentifier();
    325 
     334    /*static*/ inline ClassIdentifier<T>* ClassIdentifier<T>::getIdentifier()
     335    {
     336        if (ClassIdentifier<T>::classIdentifier_s == NULL)
     337            ClassIdentifier<T>::classIdentifier_s = (ClassIdentifier<T>*) IdentifierManager::getInstance().getIdentifierByTypeInfo(typeid(T));
     338
     339        OrxVerify(ClassIdentifier<T>::classIdentifier_s != NULL, "Did you forget to register the class of type " << typeid(T).name() << "?");
    326340        return ClassIdentifier<T>::classIdentifier_s;
    327     }
    328 
    329     /**
    330         @brief Does the same as getIdentifier() but sets the name if this wasn't done yet.
    331         @param name The name of this Identifier
    332         @return The Identifier
    333     */
    334     template <class T>
    335     inline ClassIdentifier<T>* ClassIdentifier<T>::getIdentifier(const std::string& name)
    336     {
    337         ClassIdentifier<T>* identifier = ClassIdentifier<T>::getIdentifier();
    338         identifier->setName(name);
    339         return identifier;
    340     }
    341 
    342     /**
    343         @brief Assigns the static field for the identifier singleton.
    344     */
    345     template <class T>
    346     /*static */ void ClassIdentifier<T>::initializeIdentifier()
    347     {
    348         // create a new identifier anyway. Will be deleted if not used.
    349         ClassIdentifier<T>* proposal = new ClassIdentifier<T>();
    350 
    351         // Get the entry from the map
    352         ClassIdentifier<T>::classIdentifier_s = (ClassIdentifier<T>*)IdentifierManager::getInstance().getGloballyUniqueIdentifier(proposal);
    353 
    354         if (ClassIdentifier<T>::classIdentifier_s == proposal)
    355             orxout(verbose, context::identifier) << "Requested Identifier for " << proposal->getTypeidName() << " was not yet existing and got created." << endl;
    356         else
    357         {
    358             orxout(verbose, context::identifier) << "Requested Identifier for " << proposal->getTypeidName() << " was already existing and got assigned." << endl;
    359             delete proposal; // delete proposal (it is not used anymore)
    360         }
    361341    }
    362342
     
    375355            IdentifierManager::getInstance().createdObject(object);
    376356
    377             this->setConfigValues(object, object);
     357            if (Identifier::initConfigValues_s)
     358                this->setConfigValues(object, object);
     359
    378360            return true;
    379361        }
     
    420402
    421403    /**
     404     * @brief Destroy all objects of this class (must be Listable).
     405     * Destroyables are destroyed with destroy(), all other classes with delete.
     406     */
     407    template <class T>
     408    void ClassIdentifier<T>::destroyObjects()
     409    {
     410        this->destroyObjects((T*)0);
     411    }
     412
     413    /**
     414     * @brief Only searches and destroys objects if is a @ref Listable
     415     */
     416    template <class T>
     417    void ClassIdentifier<T>::destroyObjects(Listable*)
     418    {
     419        ObjectListBase* objectList = Context::getRootContext()->getObjectList(this);
     420        ObjectListElement<T>* begin = static_cast<ObjectListElement<T>*>(objectList->begin());
     421        ObjectListElement<T>* end = static_cast<ObjectListElement<T>*>(objectList->end());
     422        for (typename ObjectList<T>::iterator it = begin; it != end; )
     423            this->destroyObject(*(it++));
     424    }
     425
     426    template <class T>
     427    void ClassIdentifier<T>::destroyObjects(void*)
     428    {
     429        // no action
     430    }
     431
     432    /**
     433     * @brief Call 'object->destroy()' for Destroyables and 'delete object' for all other types.
     434     */
     435    template <class T>
     436    void ClassIdentifier<T>::destroyObject(Destroyable* object)
     437    {
     438        object->destroy();
     439    }
     440
     441    template <class T>
     442    void ClassIdentifier<T>::destroyObject(void* object)
     443    {
     444        delete static_cast<Identifiable*>(object);
     445    }
     446
     447    /**
    422448        @brief Updates the config-values of all existing objects of this class by calling their setConfigValues() function.
    423449    */
     
    438464
    439465        if (updateChildren)
    440             for (std::set<const Identifier*>::const_iterator it = this->getChildrenBegin(); it != this->getChildrenEnd(); ++it)
     466            for (std::set<const Identifier*>::const_iterator it = this->getChildren().begin(); it != this->getChildren().end(); ++it)
    441467                (*it)->updateConfigValues(false);
    442468    }
  • code/trunk/src/libraries/core/class/IdentifierManager.cc

    r9667 r10624  
    3737
    3838#include "util/StringUtils.h"
    39 #include "core/CoreIncludes.h"
     39#include "core/Core.h"
    4040#include "core/config/ConfigValueContainer.h"
    4141#include "core/XMLPort.h"
     
    4444namespace orxonox
    4545{
    46     /* static */ IdentifierManager& IdentifierManager::getInstance()
    47     {
    48         static IdentifierManager instance;
    49         return instance;
    50     }
     46    IdentifierManager* IdentifierManager::singletonPtr_s = 0;
    5147
    5248    IdentifierManager::IdentifierManager()
    5349    {
    5450        this->hierarchyCreatingCounter_s = 0;
    55         this->classIDCounter_s = 0;
    56     }
    57 
    58     /**
    59         @brief Returns an identifier by name and adds it if not available
    60         @param proposal A pointer to a newly created identifier for the case of non existence in the map
    61         @return The identifier (unique instance)
    62     */
    63     Identifier* IdentifierManager::getGloballyUniqueIdentifier(Identifier* proposal)
    64     {
    65         const std::string& typeidName = proposal->getTypeidName();
    66         std::map<std::string, Identifier*>::const_iterator it = this->identifierByTypeidName_.find(typeidName);
    67 
    68         if (it != this->identifierByTypeidName_.end())
    69         {
    70             // There is already an entry: return it
    71             return it->second;
    72         }
    73         else
    74         {
    75             // There is no entry: put the proposal into the map and return it
    76             this->identifierByTypeidName_[typeidName] = proposal;
    77             return proposal;
    78         }
     51        this->recordTraceForIdentifier_ = NULL;
    7952    }
    8053
     
    8255     * Registers the identifier in all maps of the IdentifierManager.
    8356     */
    84     void IdentifierManager::addIdentifierToLookupMaps(Identifier* identifier)
    85     {
    86         const std::string& typeidName = identifier->getTypeidName();
    87         if (this->identifierByTypeidName_.find(typeidName) != this->identifierByTypeidName_.end())
    88         {
    89             this->identifierByString_[identifier->getName()] = identifier;
    90             this->identifierByLowercaseString_[getLowercase(identifier->getName())] = identifier;
    91             this->identifierByNetworkId_[identifier->getNetworkID()] = identifier;
    92         }
    93         else
    94             orxout(internal_warning) << "Trying to add an identifier to lookup maps which is not known to IdentifierManager" << endl;
     57    void IdentifierManager::addIdentifier(Identifier* identifier)
     58    {
     59        orxout(verbose, context::identifier) << "Adding identifier for " << identifier->getName() << " / " << identifier->getTypeInfo().name() << endl;
     60
     61        this->identifiers_.insert(identifier);
     62        this->identifierByString_[identifier->getName()] = identifier;
     63        this->identifierByLowercaseString_[getLowercase(identifier->getName())] = identifier;
     64        this->identifierByNetworkId_[identifier->getNetworkID()] = identifier;
     65    }
     66
     67    /**
     68     * Unregisters the identifier from all maps of the IdentifierManager.
     69     */
     70    void IdentifierManager::removeIdentifier(Identifier* identifier)
     71    {
     72        this->identifiers_.erase(identifier);
     73        this->identifierByString_.erase(identifier->getName());
     74        this->identifierByLowercaseString_.erase(getLowercase(identifier->getName()));
     75        this->identifierByNetworkId_.erase(identifier->getNetworkID());
    9576    }
    9677
     
    11293        {
    11394            Context temporaryContext(NULL);
    114             for (std::map<std::string, Identifier*>::const_iterator it = this->identifierByTypeidName_.begin(); it != this->identifierByTypeidName_.end(); ++it)
     95            for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
    11596            {
    116                 orxout(verbose, context::identifier) << "Initialize ClassIdentifier<" << it->second->getName() << ">-Singleton." << endl;
     97                Identifier* identifier = (*it);
     98                if (identifier->isInitialized())
     99                    continue;
     100
     101                orxout(verbose, context::identifier) << "Initialize ClassIdentifier<" << identifier->getName() << ">-Singleton." << endl;
    117102                // To initialize the identifier, we create a new object and delete it afterwards.
    118                 if (it->second->hasFactory())
     103                if (identifier->hasFactory())
    119104                {
    120                     this->identifiersOfNewObject_.clear();
    121                     Identifiable* temp = it->second->fabricate(&temporaryContext);
    122                     if (temp->getIdentifier() != it->second)
    123                         orxout(internal_error) << "Newly created object of type " << it->second->getName() << " has unexpected identifier. Did you forget to use RegisterObject(classname)?" << endl;
     105                    this->identifierTraceOfNewObject_.clear();
     106                    this->recordTraceForIdentifier_ = identifier;
     107
     108                    Identifiable* temp = identifier->fabricate(&temporaryContext);
     109
     110                    this->recordTraceForIdentifier_ = NULL;
     111
     112                    if (temp->getIdentifier() != identifier)
     113                        orxout(internal_error) << "Newly created object of type " << identifier->getName() << " has unexpected identifier. Did you forget to use RegisterObject(classname)?" << endl;
     114
     115                    identifier->initializeParents(this->identifierTraceOfNewObject_[temp]);
     116
    124117                    delete temp;
    125 
    126                     it->second->initializeParents(this->identifiersOfNewObject_);
    127118                }
    128                 else
    129                     it->second->initializeDirectParentsOfAbstractClass();
    130 
    131                 initializedIdentifiers.insert(it->second);
     119
     120                initializedIdentifiers.insert(identifier);
    132121            }
    133122
     
    138127
    139128        // finish the initialization of all identifiers
    140         for (std::map<std::string, Identifier*>::const_iterator it = this->identifierByTypeidName_.begin(); it != this->identifierByTypeidName_.end(); ++it)
    141         {
    142             if (initializedIdentifiers.find(it->second) != initializedIdentifiers.end())
    143                 it->second->finishInitialization();
    144             else
    145                 orxout(internal_error) << "Identifier was registered late and is not initialized: " << it->second->getName() << " / " << it->second->getTypeidName() << endl;
    146         }
     129        for (std::set<Identifier*>::const_iterator it = initializedIdentifiers.begin(); it != initializedIdentifiers.end(); ++it)
     130            (*it)->finishInitialization();
     131
     132        // only check class hierarchy in dev mode because it's an expensive operation and it requires a developer to fix detected problems anyway.
     133        if (!Core::exists() || Core::getInstance().getConfig()->inDevMode())
     134            this->verifyClassHierarchy(initializedIdentifiers);
    147135
    148136        this->stopCreatingHierarchy();
     
    151139
    152140    /**
    153         @brief Destroys all Identifiers. Called when exiting the program.
    154     */
    155     void IdentifierManager::destroyAllIdentifiers()
    156     {
    157         for (std::map<std::string, Identifier*>::iterator it = this->identifierByTypeidName_.begin(); it != this->identifierByTypeidName_.end(); ++it)
    158             delete (it->second);
    159 
    160         this->identifierByTypeidName_.clear();
    161         this->identifierByString_.clear();
    162         this->identifierByLowercaseString_.clear();
    163         this->identifierByNetworkId_.clear();
     141     * Verifies if the class hierarchy is consistent with the RTTI.
     142     */
     143    void IdentifierManager::verifyClassHierarchy(const std::set<Identifier*>& initializedIdentifiers)
     144    {
     145        // check if there are any uninitialized identifiers remaining
     146        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
     147            if (!(*it)->isInitialized())
     148                orxout(internal_error) << "Identifier was registered late and is not initialized: " << (*it)->getName() << " / " << (*it)->getTypeInfo().name() << endl;
     149
     150        // for all initialized identifiers, check if a sample instance behaves as expected according to the class hierarchy
     151        Context temporaryContext(NULL);
     152        for (std::set<Identifier*>::const_iterator it1 = initializedIdentifiers.begin(); it1 != initializedIdentifiers.end(); ++it1)
     153        {
     154            if (!(*it1)->hasFactory())
     155                continue;
     156
     157            Identifiable* temp = (*it1)->fabricate(&temporaryContext);
     158
     159            for (std::set<Identifier*>::const_iterator it2 = this->identifiers_.begin(); it2 != this->identifiers_.end(); ++it2)
     160            {
     161                bool isA_AccordingToRtti = (*it2)->canDynamicCastObjectToIdentifierClass(temp);
     162                bool isA_AccordingToClassHierarchy = temp->isA((*it2));
     163
     164                if (isA_AccordingToRtti != isA_AccordingToClassHierarchy)
     165                {
     166                    orxout(internal_error) << "Class hierarchy does not match RTTI: Class hierarchy claims that " << (*it1)->getName() <<
     167                        (isA_AccordingToClassHierarchy ? " is a " : " is not a ") << (*it2)->getName() << " but RTTI says the opposite." << endl;
     168                }
     169            }
     170
     171            delete temp;
     172        }
     173        orxout(internal_info) << "Class hierarchy matches RTTI" << endl;
     174
     175        size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
     176        if (numberOfObjects > 0)
     177            orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
     178    }
     179
     180    /**
     181     * @brief Resets all Identifiers.
     182     */
     183    void IdentifierManager::destroyClassHierarchy()
     184    {
     185        orxout(internal_status) << "Destroy class-hierarchy" << endl;
     186        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
     187            (*it)->reset();
    164188    }
    165189
     
    170194    {
    171195        if (this->isCreatingHierarchy())
    172             this->identifiersOfNewObject_.insert(identifiable->getIdentifier());
     196        {
     197            if (this->recordTraceForIdentifier_)
     198            {
     199                std::list<const Identifier*>& traceForObject = this->identifierTraceOfNewObject_[identifiable];
     200                if (std::find(traceForObject.begin(), traceForObject.end(), identifiable->getIdentifier()) != traceForObject.end())
     201                {
     202                    orxout(internal_warning) << this->recordTraceForIdentifier_->getName() << " inherits two times from " <<
     203                        identifiable->getIdentifier()->getName() << ". Did you forget to use virtual inheritance?" << endl;
     204                }
     205                traceForObject.push_back(identifiable->getIdentifier());
     206            }
     207        }
    173208        else
    174209            orxout(internal_warning) << "createdObject() called outside of class hierarchy creation" << endl;
     
    218253
    219254    /**
     255        @brief Returns the Identifier with a given typeid-name.
     256        @param name The typeid-name of the wanted Identifier
     257        @return The Identifier
     258    */
     259    Identifier* IdentifierManager::getIdentifierByTypeInfo(const std::type_info& typeInfo)
     260    {
     261        // TODO: use std::type_index and a map to find identifiers by type_info (only with c++11)
     262        for (std::set<Identifier*>::iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
     263            if ((*it)->getTypeInfo() == typeInfo)
     264                return (*it);
     265        return 0;
     266    }
     267
     268    /**
    220269        @brief Cleans the NetworkID map (needed on clients for correct initialization)
    221270    */
  • code/trunk/src/libraries/core/class/IdentifierManager.h

    r9667 r10624  
    3939#include <map>
    4040#include <set>
     41#include <list>
    4142#include <string>
     43
     44#include "util/Singleton.h"
    4245
    4346namespace orxonox
    4447{
    45     class _CoreExport IdentifierManager
     48    class _CoreExport IdentifierManager : public Singleton<IdentifierManager>
    4649    {
     50        friend class Singleton<IdentifierManager>;
     51
    4752        public:
    48             static IdentifierManager& getInstance();
     53            IdentifierManager();
     54            ~IdentifierManager() {}
    4955
    50             Identifier* getGloballyUniqueIdentifier(Identifier* proposal);
    51             void addIdentifierToLookupMaps(Identifier* identifier);
    52 
    53             unsigned int getUniqueClassId()
    54                 { return this->classIDCounter_s++; }
     56            void addIdentifier(Identifier* identifier);
     57            void removeIdentifier(Identifier* identifier);
    5558
    5659
     
    5962            /////////////////////////////
    6063            void createClassHierarchy();
    61             void destroyAllIdentifiers();
     64            void verifyClassHierarchy(const std::set<Identifier*>& initializedIdentifiers);
     65            void destroyClassHierarchy();
    6266
    6367            void createdObject(Identifiable* identifiable);
     
    7478            Identifier* getIdentifierByLowercaseString(const std::string& name);
    7579            Identifier* getIdentifierByID(uint32_t id);
     80            Identifier* getIdentifierByTypeInfo(const std::type_info& typeInfo);
    7681
    7782            void clearNetworkIDs();
     
    8893
    8994        private:
    90             IdentifierManager();
    91             IdentifierManager(const IdentifierManager&);
    92             ~IdentifierManager() {}
     95            IdentifierManager(const IdentifierManager&); // not implemented
    9396
    9497            /// Increases the hierarchyCreatingCounter_s variable, causing all new objects to store their parents.
     
    99102                { hierarchyCreatingCounter_s--; }
    100103
    101             std::map<std::string, Identifier*> identifierByTypeidName_;      //!< Map with the names as received by typeid(). This is only used internally.
    102 
     104            std::set<Identifier*> identifiers_;                              //!< All identifiers. This is only used internally.
    103105            std::map<std::string, Identifier*> identifierByString_;          //!< Map that stores all Identifiers with their names.
    104106            std::map<std::string, Identifier*> identifierByLowercaseString_; //!< Map that stores all Identifiers with their names in lowercase.
     
    106108
    107109            int hierarchyCreatingCounter_s;                         //!< Bigger than zero if at least one Identifier stores its parents (its an int instead of a bool to avoid conflicts with multithreading)
    108             std::set<const Identifier*> identifiersOfNewObject_;    //!< Used while creating the object hierarchy to keep track of the identifiers of a newly created object
    109             unsigned int classIDCounter_s;                          //!< counter for the unique classIDs
     110
     111            /// Used while creating the object hierarchy to keep track of the identifiers of a newly created object (and all other objects that get created as
     112            /// a consequence of this, e.g. nested member objects).
     113            std::map<Identifiable*, std::list<const Identifier*> > identifierTraceOfNewObject_;
     114            Identifier* recordTraceForIdentifier_; //!< The identifier for which we want to record the trace of identifiers during object creation. If null, no trace is recorded.
     115
     116            static IdentifierManager* singletonPtr_s;
    110117    };
    111118}
  • code/trunk/src/libraries/core/class/OrxonoxInterface.cc

    r9667 r10624  
    3232namespace orxonox
    3333{
    34     RegisterClassNoArgs(OrxonoxInterface);
     34    RegisterClassNoArgs(OrxonoxInterface).virtualBase();
    3535
    3636    OrxonoxInterface::OrxonoxInterface()
  • code/trunk/src/libraries/core/class/Super.h

    r9667 r10624  
    274274        SUPER_NOARGS(classname, functionname)
    275275
    276     #define SUPER_changedGametype(classname, functionname, ...) \
    277         SUPER_NOARGS(classname, functionname)
    278 
    279276    #define SUPER_changedUsed(classname, functionname, ...) \
    280277        SUPER_NOARGS(classname, functionname)
     
    555552        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
    556553
    557         SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(9, changedGametype, false)
    558             ()
    559         SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
    560 
    561         SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(10, changedUsed, false)
    562             ()
    563         SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
    564 
    565         SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(11, changedCarrier, false)
    566             ()
    567         SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
    568 
    569         SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(12, changedPickedUp, false)
     554        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(9, changedUsed, false)
     555            ()
     556        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
     557
     558        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(10, changedCarrier, false)
     559            ()
     560        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
     561
     562        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(11, changedPickedUp, false)
    570563            ()
    571564        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
     
    623616    SUPER_INTRUSIVE_DECLARATION(changedOverlayGroup);
    624617    SUPER_INTRUSIVE_DECLARATION(changedName);
    625     SUPER_INTRUSIVE_DECLARATION(changedGametype);
    626618    SUPER_INTRUSIVE_DECLARATION(changedUsed);
    627619    SUPER_INTRUSIVE_DECLARATION(changedCarrier);
Note: See TracChangeset for help on using the changeset viewer.