Browse Source

- Added support to declare statically whether a type is a container of children and what polymorphic type is allowed.
- Wired-up TAML readers to check for child compatibility. If not compatible then a warning is issued and the child is deleted. An example warning is "Taml: Child element 'SimObject' found under parent 'Scene' but object is restricted to children of type 'SceneObject'."
> Scene does this by simply declaring the "Children" typedef (alongside the Parent typedef) and implementing itself as a "IMPLEMENT_CONOBJECT_CHILDREN(Scene)".
> SimSet has children but it allows all SimObject which is the default so no change is required.

MelvMay-GG 12 years ago
parent
commit
11ca2e3

+ 1 - 1
engine/source/2d/scene/Scene.cc

@@ -68,7 +68,7 @@ SimObjectPtr<Scene> Scene::LoadingScene = NULL;
 
 //------------------------------------------------------------------------------
 
-IMPLEMENT_CONOBJECT(Scene);
+IMPLEMENT_CONOBJECT_CHILDREN(Scene);
 
 //------------------------------------------------------------------------------
 

+ 1 - 0
engine/source/2d/scene/Scene.h

@@ -207,6 +207,7 @@ public:
 
 private:
     typedef BehaviorComponent   Parent;
+    typedef SceneObject         Children;
 
     /// World.
     b2World*                    mpWorld;

+ 35 - 7
engine/source/console/consoleObject.h

@@ -197,6 +197,7 @@ public:
    Namespace*                 getNameSpace();
    AbstractClassRep*          getNextClass();
    AbstractClassRep*          getParentClass();
+   virtual AbstractClassRep*  getContainerChildClass() = 0;
 
    /// Helper class to see if we are a given class, or a subclass thereof.
    bool                       isClass(AbstractClassRep  *acr)
@@ -347,7 +348,7 @@ template <class T>
 class ConcreteClassRep : public AbstractClassRep
 {
 public:
-   ConcreteClassRep(const char *name, S32 netClassGroupMask, S32 netClassType, S32 netEventDir, AbstractClassRep *parent)
+   ConcreteClassRep(const char *name, S32 netClassGroupMask, S32 netClassType, S32 netEventDir, AbstractClassRep *parent )
    {
       // name is a static compiler string so no need to worry about copying or deleting
       mClassName = name;
@@ -366,14 +367,30 @@ public:
       registerClassRep(this);
    };
 
+    virtual AbstractClassRep* getContainerChildClass()
+    {
+        // Fetch container children type.
+        AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
+        if ( pChildren != NULL )
+            return pChildren;
+
+        // Fetch parent type.
+        AbstractClassRep* pParent = T::getParentStaticClassRep();
+        if ( pParent == NULL )
+            return NULL;
+
+        // Get parent container children.
+        return pParent->getContainerChildClass();
+    }
+
    /// Perform class specific initialization tasks.
    ///
    /// Link namespaces, call initPersistFields() and consoleInit().
    void init() const
    {
       // Get handle to our parent class, if any, and ourselves (we are our parent's child).
-      AbstractClassRep *parent = T::getParentStaticClassRep();
-      AbstractClassRep *child  = T::getStaticClassRep      ();
+      AbstractClassRep *parent      = T::getParentStaticClassRep();
+      AbstractClassRep *child       = T::getStaticClassRep();
 
       // If we got reps, then link those namespaces! (To get proper inheritance.)
       if(parent && child)
@@ -788,25 +805,36 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
 #define DECLARE_CONOBJECT(className)                    \
    static ConcreteClassRep<className> dynClassRep;      \
    static AbstractClassRep* getParentStaticClassRep();  \
+   static AbstractClassRep* getContainerChildStaticClassRep();      \
    static AbstractClassRep* getStaticClassRep();        \
    virtual AbstractClassRep* getClassRep() const
 
-#define IMPLEMENT_CONOBJECT(className)                                                            \
-   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }           \
-   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                      \
-   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
+#define IMPLEMENT_CONOBJECT(className)                                                              \
+   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }             \
+   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                        \
+   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }   \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                  \
+   ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
+
+#define IMPLEMENT_CONOBJECT_CHILDREN(className)                                                                     \
+   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                             \
+   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                                        \
+   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }                   \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }         \
    ConcreteClassRep<className> className::dynClassRep(#className, 0, -1, 0, className::getParentStaticClassRep())
 
 #define IMPLEMENT_CO_NETOBJECT_V1(className)                    \
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                 \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                            \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }       \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                      \
    ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeObject, 0, className::getParentStaticClassRep())
 
 #define IMPLEMENT_CO_DATABLOCK_V1(className)                                                            \
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                 \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                            \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }       \
+   AbstractClassRep* className::getContainerChildStaticClassRep() {return NULL; }                       \
    ConcreteClassRep<className> className::dynClassRep(#className, NetClassGroupGameMask, NetClassTypeDataBlock, 0, className::getParentStaticClassRep())
 
 /// @}

+ 6 - 0
engine/source/network/netConnection.h

@@ -287,36 +287,42 @@ public:
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
    ConcreteClassRep<className> className::dynClassRep(#className,NetClassGroupGameMask, NetClassTypeEvent, NetEventDirAny, className::getParentStaticClassRep())
 
 #define IMPLEMENT_CO_CLIENTEVENT_V1(className)                    \
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
    ConcreteClassRep<className> className::dynClassRep(#className,NetClassGroupGameMask, NetClassTypeEvent, NetEventDirServerToClient, className::getParentStaticClassRep())
 
 #define IMPLEMENT_CO_SERVEREVENT_V1(className)                    \
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
    ConcreteClassRep<className> className::dynClassRep(#className,NetClassGroupGameMask, NetClassTypeEvent, NetEventDirClientToServer, className::getParentStaticClassRep())
 
 #define IMPLEMENT_CO_NETEVENT(className,groupMask)                    \
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
    ConcreteClassRep<className> className::dynClassRep(#className,groupMask, NetClassTypeEvent, NetEventDirAny, className::getParentStaticClassRep())
 
 #define IMPLEMENT_CO_CLIENTEVENT(className,groupMask)                    \
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
    ConcreteClassRep<className> className::dynClassRep(#className,groupMask, NetClassTypeEvent, NetEventDirServerToClient, className::getParentStaticClassRep())
 
 #define IMPLEMENT_CO_SERVEREVENT(className,groupMask)                    \
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; } \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; } \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); } \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; } \
    ConcreteClassRep<className> className::dynClassRep(#className,groupMask, NetClassTypeEvent, NetEventDirClientToServer, className::getParentStaticClassRep())
 
 

+ 23 - 0
engine/source/persistence/taml/tamlBinaryReader.cc

@@ -271,6 +271,9 @@ void TamlBinaryReader::parseChildren( Stream& stream, TamlCallbacks* pCallbacks,
         return;
     }
 
+    // Fetch any container child class specifier.
+    AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass();
+
     // Iterate children.
     for ( U32 index = 0; index < childrenCount; ++ index )
     {
@@ -281,6 +284,26 @@ void TamlBinaryReader::parseChildren( Stream& stream, TamlCallbacks* pCallbacks,
         if ( pChildSimObject == NULL )
             return;
 
+        // Do we have a container child class?
+        if ( pContainerChildClass != NULL )
+        {
+            // Yes, so is the child object the correctly derived type?
+            if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
+            {
+                // No, so warn.
+                Con::warnf("Taml: Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
+                    pChildSimObject->getClassName(),
+                    pSimObject->getClassName(),
+                    pContainerChildClass->getClassName() );
+
+                // NOTE: We can't delete the object as it may be referenced elsewhere!
+                pChildSimObject = NULL;
+
+                // Skip.
+                continue;
+            }
+        }
+
         // Add child.
         pChildren->addTamlChild( pChildSimObject );
 

+ 27 - 4
engine/source/persistence/taml/tamlXmlReader.cc

@@ -174,6 +174,9 @@ SimObject* TamlXmlReader::parseElement( TiXmlElement* pXmlElement )
         // Fetch the Taml children.
         TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );
 
+        // Fetch any container child class specifier.
+        AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass();
+
         // Iterate siblings.
         do
         {
@@ -209,6 +212,26 @@ SimObject* TamlXmlReader::parseElement( TiXmlElement* pXmlElement )
                 if ( pChildSimObject == NULL )
                     continue;
 
+                // Do we have a container child class?
+                if ( pContainerChildClass != NULL )
+                {
+                    // Yes, so is the child object the correctly derived type?
+                    if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
+                    {
+                        // No, so warn.
+                        Con::warnf("Taml: Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
+                            pChildSimObject->getClassName(),
+                            pSimObject->getClassName(),
+                            pContainerChildClass->getClassName() );
+
+                        // NOTE: We can't delete the object as it may be referenced elsewhere!
+                        pChildSimObject = NULL;
+
+                        // Skip.
+                        continue;
+                    }
+                }
+
                 // Add child.
                 pChildren->addTamlChild( pChildSimObject );
 
@@ -263,10 +286,10 @@ void TamlXmlReader::parseAttributes( TiXmlElement* pXmlElement, SimObject* pSimO
 
         // Ignore if this is a Taml attribute.
         if (    attributeName == mTamlRefId ||
-                attributeName == mTamlRefToId ||
-                attributeName == mTamlObjectName ||
-                attributeName == mTamlRefField )
-                continue;
+            attributeName == mTamlRefToId ||
+            attributeName == mTamlObjectName ||
+            attributeName == mTamlRefField )
+            continue;
 
         // We can assume this is a field for now.
         pSimObject->setPrefixedDataField( attributeName, NULL, pAttribute->Value() );