Browse Source

Merge pull request #27 from MelvMay-GG/development

Merging the Taml custom serialization changes.
MelvMay-GG 12 years ago
parent
commit
0fda06d
44 changed files with 2266 additions and 1805 deletions
  1. 38 32
      engine/source/2d/assets/ImageAsset.cc
  2. 2 2
      engine/source/2d/assets/ImageAsset.h
  3. 4 4
      engine/source/2d/assets/ParticleAsset.cc
  4. 2 2
      engine/source/2d/assets/ParticleAsset.h
  5. 4 4
      engine/source/2d/assets/ParticleAssetEmitter.cc
  6. 2 2
      engine/source/2d/assets/ParticleAssetEmitter.h
  7. 74 39
      engine/source/2d/assets/ParticleAssetField.cc
  8. 2 2
      engine/source/2d/assets/ParticleAssetField.h
  9. 22 19
      engine/source/2d/assets/ParticleAssetFieldCollection.cc
  10. 2 2
      engine/source/2d/assets/ParticleAssetFieldCollection.h
  11. 18 15
      engine/source/2d/core/SpriteBatch.cc
  12. 2 2
      engine/source/2d/core/SpriteBatch.h
  13. 34 28
      engine/source/2d/core/SpriteBatchItem.cc
  14. 2 2
      engine/source/2d/core/SpriteBatchItem.h
  15. 733 606
      engine/source/2d/scene/Scene.cc
  16. 3 3
      engine/source/2d/scene/Scene.h
  17. 14 14
      engine/source/2d/sceneobject/CompositeSprite.cc
  18. 2 2
      engine/source/2d/sceneobject/CompositeSprite.h
  19. 276 171
      engine/source/2d/sceneobject/SceneObject.cc
  20. 2 2
      engine/source/2d/sceneobject/SceneObject.h
  21. 26 23
      engine/source/assets/assetQuery.cc
  22. 4 4
      engine/source/assets/assetQuery.h
  23. 45 39
      engine/source/assets/assetTagsManifest.cc
  24. 4 4
      engine/source/assets/assetTagsManifest.h
  25. 61 49
      engine/source/component/behaviors/behaviorComponent.cpp
  26. 4 4
      engine/source/component/behaviors/behaviorComponent.h
  27. 0 2
      engine/source/memory/frameAllocator.h
  28. 59 62
      engine/source/persistence/taml/taml.cc
  29. 6 5
      engine/source/persistence/taml/taml.h
  30. 110 97
      engine/source/persistence/taml/tamlBinaryReader.cc
  31. 2 1
      engine/source/persistence/taml/tamlBinaryReader.h
  32. 116 83
      engine/source/persistence/taml/tamlBinaryWriter.cc
  33. 3 2
      engine/source/persistence/taml/tamlBinaryWriter.h
  34. 4 4
      engine/source/persistence/taml/tamlCallbacks.h
  35. 9 56
      engine/source/persistence/taml/tamlCustom.cc
  36. 353 254
      engine/source/persistence/taml/tamlCustom.h
  37. 2 2
      engine/source/persistence/taml/tamlWriteNode.cc
  38. 1 3
      engine/source/persistence/taml/tamlWriteNode.h
  39. 98 78
      engine/source/persistence/taml/tamlXmlReader.cc
  40. 2 1
      engine/source/persistence/taml/tamlXmlReader.h
  41. 107 73
      engine/source/persistence/taml/tamlXmlWriter.cc
  42. 2 1
      engine/source/persistence/taml/tamlXmlWriter.h
  43. 3 3
      engine/source/sim/simObject.h
  44. 7 2
      modules/ToyAssets/1/assets/particles/bonfire.asset.taml

+ 38 - 32
engine/source/2d/assets/ImageAsset.cc

@@ -109,8 +109,8 @@ IMPLEMENT_CONOBJECT(ImageAsset);
 
 static bool explicitCellPropertiesInitialized = false;
 
-static StringTableEntry cellCustomPropertyName;
-static StringTableEntry cellAliasName;
+static StringTableEntry cellCustomNodeName;
+static StringTableEntry cellNodeName;
 static StringTableEntry cellOffsetName;
 static StringTableEntry cellWidthName;
 static StringTableEntry cellHeightName;
@@ -184,8 +184,8 @@ ImageAsset::ImageAsset() :  mImageFile(StringTable->EmptyString),
     // Initialize explicit cell field names.
     if ( !explicitCellPropertiesInitialized )
     {
-        cellCustomPropertyName      = StringTable->insert( "Cells" );
-        cellAliasName               = StringTable->insert( "Cell" );
+        cellCustomNodeName          = StringTable->insert( "Cells" );
+        cellNodeName                = StringTable->insert( "Cell" );
         cellOffsetName              = StringTable->insert( "Offset" );
         cellWidthName               = StringTable->insert( "Width" );
         cellHeightName              = StringTable->insert( "Height" );
@@ -868,20 +868,20 @@ void ImageAsset::onTamlPostWrite( void )
 
 //------------------------------------------------------------------------------
 
-void ImageAsset::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ImageAsset_OnTamlCustomWrite);
 
     // Call parent.
-    Parent::onTamlCustomWrite( customProperties );
+    Parent::onTamlCustomWrite( customNodes );
 
     // Finish if not in explicit mode.
     if ( !mExplicitMode )
         return;
 
-    // Add cell custom property.
-    TamlCustomProperty* pCellProperty = customProperties.addProperty( cellCustomPropertyName );
+    // Add cell custom node.
+    TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeName );
 
     // Iterate explicit frames.
     for( typeExplicitFrameAreaVector::iterator frameItr = mExplicitFrames.begin(); frameItr != mExplicitFrames.end(); ++frameItr )
@@ -890,49 +890,52 @@ void ImageAsset::onTamlCustomWrite( TamlCustomProperties& customProperties )
         const FrameArea::PixelArea& pixelArea = *frameItr;
 
         // Add cell alias.
-        TamlPropertyAlias* pCellAlias = pCellProperty->addAlias( cellAliasName );
+        TamlCustomNode* pCellNode = pCustomCellNodes->addNode( cellNodeName );
 
         // Add cell properties.
-        pCellAlias->addField( cellOffsetName, pixelArea.mPixelOffset );
-        pCellAlias->addField( cellWidthName, pixelArea.mPixelWidth );
-        pCellAlias->addField( cellHeightName, pixelArea.mPixelHeight );
+        pCellNode->addField( cellOffsetName, pixelArea.mPixelOffset );
+        pCellNode->addField( cellWidthName, pixelArea.mPixelWidth );
+        pCellNode->addField( cellHeightName, pixelArea.mPixelHeight );
     }
 }
 
 //-----------------------------------------------------------------------------
 
-void ImageAsset::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void ImageAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
 
     // Call parent.
-    Parent::onTamlCustomRead( customProperties );
+    Parent::onTamlCustomRead( customNodes );
 
-    // Find cell custom property
-    const TamlCustomProperty* pCellProperty = customProperties.findProperty( cellCustomPropertyName );
+    // Find cell custom node.
+    const TamlCustomNode* pCustomCellNodes = customNodes.findNode( cellCustomNodeName );
 
     // Finish if we don't have explicit cells.
-    if ( pCellProperty == NULL )
+    if ( pCustomCellNodes == NULL )
         return;
 
     // Set explicit mode.
     mExplicitMode = true;
 
+    // Fetch children cell nodes.
+    const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
+
     // Iterate cells.
-    for( TamlCustomProperty::const_iterator propertyAliasItr = pCellProperty->begin(); propertyAliasItr != pCellProperty->end(); ++propertyAliasItr )
+    for( TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr )
     {
-        // Fetch property alias.
-        TamlPropertyAlias* pPropertyAlias = *propertyAliasItr;
+        // Fetch cell node.
+        TamlCustomNode* pCellNode = *cellNodeItr;
 
-        // Fetch alias name.
-        StringTableEntry aliasName = pPropertyAlias->mAliasName;
+        // Fetch node name.
+        StringTableEntry nodeName = pCellNode->getNodeName();
 
         // Is this a valid alias?
-        if ( aliasName != cellAliasName )
+        if ( nodeName != cellNodeName )
         {
             // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom alias name of '%s'.  Only '%s' is valid.", aliasName, cellAliasName );
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, cellNodeName );
             continue;
         }
 
@@ -940,27 +943,30 @@ void ImageAsset::onTamlCustomRead( const TamlCustomProperties& customProperties
         S32 cellWidth = 0;
         S32 cellHeight = 0;
 
+        // Fetch fields.
+        const TamlCustomFieldVector& fields = pCellNode->getFields();
+
         // Iterate property fields.
-        for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
+        for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
         {
-            // Fetch property field.
-            TamlPropertyField* pPropertyField = *propertyFieldItr;
+            // Fetch field.
+            const TamlCustomField* pField = *fieldItr;
 
-            // Fetch property field name.
-            StringTableEntry fieldName = pPropertyField->getFieldName();
+            // Fetch field name.
+            StringTableEntry fieldName = pField->getFieldName();
 
             // Check common fields.
             if ( fieldName == cellOffsetName )
             {
-                pPropertyField->getFieldValue( cellOffset );
+                pField->getFieldValue( cellOffset );
             }
             else if ( fieldName == cellWidthName )
             {
-                pPropertyField->getFieldValue( cellWidth );
+                pField->getFieldValue( cellWidth );
             }
             else if ( fieldName == cellHeightName )
             {
-                pPropertyField->getFieldValue( cellHeight );
+                pField->getFieldValue( cellHeight );
             }
             else
             {

+ 2 - 2
engine/source/2d/assets/ImageAsset.h

@@ -243,8 +243,8 @@ protected:
     /// Taml callbacks.
     virtual void onTamlPreWrite( void );
     virtual void onTamlPostWrite( void );
-    virtual void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    virtual void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 
 protected:

+ 4 - 4
engine/source/2d/assets/ParticleAsset.cc

@@ -474,22 +474,22 @@ void ParticleAsset::moveEmitter( S32 fromIndex, S32 toIndex )
 
 //------------------------------------------------------------------------------
 
-void ParticleAsset::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void ParticleAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAsset_OnTamlCustomWrite);
 
     // Write the fields.
-    mParticleFields.onTamlCustomWrite( customProperties );
+    mParticleFields.onTamlCustomWrite( customNodes );
 }
 
 //-----------------------------------------------------------------------------
 
-void ParticleAsset::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void ParticleAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAsset_OnTamlCustomRead);
 
     // Read the fields.
-    mParticleFields.onTamlCustomRead( customProperties );
+    mParticleFields.onTamlCustomRead( customNodes );
 }

+ 2 - 2
engine/source/2d/assets/ParticleAsset.h

@@ -160,8 +160,8 @@ public:
 protected:
     virtual void initializeAsset( void );
 
-    void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 protected:
     static bool setLifetime(void* obj, const char* data)                    { static_cast<ParticleAsset*>(obj)->setLifetime(dAtof(data)); return false; }

+ 4 - 4
engine/source/2d/assets/ParticleAssetEmitter.cc

@@ -489,23 +489,23 @@ void ParticleAssetEmitter::onAssetRefreshed( AssetPtrBase* pAssetPtrBase )
 
 //------------------------------------------------------------------------------
 
-void ParticleAssetEmitter::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void ParticleAssetEmitter::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAssetEmitter_OnTamlCustomWrite);
 
     // Write the fields.
-    mParticleFields.onTamlCustomWrite( customProperties );
+    mParticleFields.onTamlCustomWrite( customNodes );
 }
 
 //-----------------------------------------------------------------------------
 
-void ParticleAssetEmitter::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void ParticleAssetEmitter::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAssetEmitter_OnTamlCustomRead);
 
     // Read the fields.
-    mParticleFields.onTamlCustomRead( customProperties );
+    mParticleFields.onTamlCustomRead( customNodes );
 }
 

+ 2 - 2
engine/source/2d/assets/ParticleAssetEmitter.h

@@ -260,8 +260,8 @@ private:
     virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
 
 protected:
-    void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
     static bool     setEmitterName(void* obj, const char* data)                         { static_cast<ParticleAssetEmitter*>(obj)->setEmitterName( data ); return false; }
     static bool     setEmitterType(void* obj, const char* data)                         { static_cast<ParticleAssetEmitter*>(obj)->setEmitterType( getEmitterTypeEnum(data) ); return false; }

+ 74 - 39
engine/source/2d/assets/ParticleAssetField.cc

@@ -50,6 +50,10 @@ static StringTableEntry particleAssetFieldDefaultValueName;
 static StringTableEntry particleAssetFieldValueScaleName;
 static StringTableEntry particleAssetFieldDataKeysName;
 
+static StringTableEntry particleAssetFieldDataKeyName;
+static StringTableEntry particleAssetFieldDataKeyTimeName;
+static StringTableEntry particleAssetFieldDataKeyValueName;
+
 ParticleAssetField::DataKey ParticleAssetField::BadDataKey( -1.0f, 0.0f );
 
 //-----------------------------------------------------------------------------
@@ -78,6 +82,10 @@ ParticleAssetField::ParticleAssetField() :
         particleAssetFieldValueScaleName   = StringTable->insert( "ValueScale" );
         particleAssetFieldDataKeysName     = StringTable->insert( "Keys" );
 
+        particleAssetFieldDataKeyName      = StringTable->insert( "Key" );
+        particleAssetFieldDataKeyTimeName  = StringTable->insert( "Time" );
+        particleAssetFieldDataKeyValueName = StringTable->insert( "Value" );
+
         // Flag as initialized.
         particleAssetFieldPropertiesInitialized = true;
     }
@@ -509,34 +517,34 @@ F32 ParticleAssetField::calculateFieldBVLE( const ParticleAssetField& base, cons
 
 //------------------------------------------------------------------------------
 
-void ParticleAssetField::onTamlCustomWrite( TamlCustomProperty* pCustomProperty )
+void ParticleAssetField::onTamlCustomWrite( TamlCustomNode* pCustomNode )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAssetField_OnTamlCustomWrite);
 
-    // Add a alias (ignore it if there ends up being no properties).
-    TamlPropertyAlias* pPropertyAlias = pCustomProperty->addAlias( getFieldName(), true );
+    // Add a child (ignore it if there ends up being no children).
+    TamlCustomNode* pAssetField = pCustomNode->addNode( getFieldName(), true );
 
     // Sanity!
-    AssertFatal( pPropertyAlias != NULL, "ParticleAssetField::onTamlCustomWrite() - Could not create field alias." );
+    AssertFatal( pAssetField != NULL, "ParticleAssetField::onTamlCustomWrite() - Could not create field." );
 
     if ( mValueBoundsDirty && (mNotEqual( getMinValue(), 0.0f ) || mNotEqual( getMaxValue(), 0.0f )) )
     {
-        pPropertyAlias->addField( particleAssetFieldMinValueName, getMinValue() );
-        pPropertyAlias->addField( particleAssetFieldMaxValueName, getMaxValue() );
+        pAssetField->addField( particleAssetFieldMinValueName, getMinValue() );
+        pAssetField->addField( particleAssetFieldMaxValueName, getMaxValue() );
     }
     
     if ( mValueBoundsDirty && mNotEqual( getMaxTime(), 1.0f ) )
-        pPropertyAlias->addField( particleAssetFieldMaxTimeName, getMaxTime() );
+        pAssetField->addField( particleAssetFieldMaxTimeName, getMaxTime() );
 
     if ( mValueBoundsDirty && mNotEqual( getDefaultValue(), 1.0f ) )
-        pPropertyAlias->addField( particleAssetFieldDefaultValueName, getDefaultValue() );
+        pAssetField->addField( particleAssetFieldDefaultValueName, getDefaultValue() );
 
     if ( mNotEqual( getValueScale(), 1.0f ) )
-        pPropertyAlias->addField( particleAssetFieldValueScaleName, getValueScale() );
+        pAssetField->addField( particleAssetFieldValueScaleName, getValueScale() );
 
     if ( mNotEqual( getRepeatTime(), 1.0f ) )
-        pPropertyAlias->addField( particleAssetFieldRepeatTimeName, getRepeatTime() );
+        pAssetField->addField( particleAssetFieldRepeatTimeName, getRepeatTime() );
 
     // Fetch key count.
     const U32 keyCount = getDataKeyCount();
@@ -549,29 +557,24 @@ void ParticleAssetField::onTamlCustomWrite( TamlCustomProperty* pCustomProperty
     if ( keyCount == 1 && mIsEqual(mDataKeys[0].mTime, 0.0f) && mIsEqual(mDataKeys[0].mValue, mDefaultValue) )
         return;
 
-    // Format the keys,
-    char keysBuffer[MAX_TAML_PROPERTY_FIELDVALUE_LENGTH];
-    char* pKeysBuffer = keysBuffer;
-    S32 bufferSize = sizeof(keysBuffer);
-
     // Iterate the keys.
     for( U32 index = 0; index < keyCount; ++index )
     {
         // Fetch the data key.
         const DataKey& dataKey = mDataKeys[index];
 
-        // Format the key.
-        S32 written = dSprintf( pKeysBuffer, bufferSize, index == 0 ? "%.5g %.5g" : " %.5g %.5g", dataKey.mTime, dataKey.mValue );
-        pKeysBuffer += written;
-        bufferSize -= written;
-    }
+        // Add a key node.
+        TamlCustomNode* pKeyNode = pCustomNode->addNode( particleAssetFieldDataKeyName );
 
-    pPropertyAlias->addField( particleAssetFieldDataKeysName, keysBuffer );
+        // Add key fields.
+        pKeyNode->addField( particleAssetFieldDataKeyTimeName, dataKey.mTime );
+        pKeyNode->addField( particleAssetFieldDataKeyValueName, dataKey.mValue );
+    }
 }
 
 //-----------------------------------------------------------------------------
 
-void ParticleAssetField::onTamlCustomRead( const TamlPropertyAlias* pPropertyAlias )
+void ParticleAssetField::onTamlCustomRead( const TamlCustomNode* pCustomNode )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAssetField_OnTamlCustomRead);
@@ -590,46 +593,49 @@ void ParticleAssetField::onTamlCustomRead( const TamlPropertyAlias* pPropertyAli
     // Clear the existing keys.
     mDataKeys.clear();
 
-    // Iterate property fields.
-    for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
+    // Fetch fields.
+    const TamlCustomFieldVector& fields = pCustomNode->getFields();
+
+    // Iterate fields.
+    for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
     {
-        // Fetch property field.
-        TamlPropertyField* pPropertyField = *propertyFieldItr;
+        // Fetch field.
+        TamlCustomField* pField = *fieldItr;
 
         // Fetch property field name.
-        StringTableEntry fieldName = pPropertyField->getFieldName();
+        StringTableEntry fieldName = pField->getFieldName();
 
         if ( fieldName == particleAssetFieldRepeatTimeName )
         {
-            pPropertyField->getFieldValue( repeatTime );
+            pField->getFieldValue( repeatTime );
         }
         else if ( fieldName == particleAssetFieldMaxTimeName )
         {
-            pPropertyField->getFieldValue( maxTime );
+            pField->getFieldValue( maxTime );
             mValueBoundsDirty = true;
         }
         else if ( fieldName == particleAssetFieldMinValueName )
         {
-            pPropertyField->getFieldValue( minValue );
+            pField->getFieldValue( minValue );
             mValueBoundsDirty = true;
         }
         else if ( fieldName == particleAssetFieldMaxValueName )
         {
-            pPropertyField->getFieldValue( maxValue );
+            pField->getFieldValue( maxValue );
             mValueBoundsDirty = true;
         }
         else if ( fieldName == particleAssetFieldDefaultValueName )
         {
-            pPropertyField->getFieldValue( defaultValue );
+            pField->getFieldValue( defaultValue );
             mValueBoundsDirty = true;
         }
         else if ( fieldName == particleAssetFieldValueScaleName )
         {
-            pPropertyField->getFieldValue( valueScale );
+            pField->getFieldValue( valueScale );
         }
         else if ( fieldName == particleAssetFieldDataKeysName )
         {
-            const char* pDataKeys = pPropertyField->getFieldValue();
+            const char* pDataKeys = pField->getFieldValue();
             const S32 elementCount = StringUnit::getUnitCount( pDataKeys, " ,\t" );
 
             // Are there a valid number of elements?
@@ -652,6 +658,39 @@ void ParticleAssetField::onTamlCustomRead( const TamlPropertyAlias* pPropertyAli
         }
     }
 
+    // Fetch any children.
+    const TamlCustomNodeVector& children = pCustomNode->getChildren();
+
+    // Iterate node children.
+    for( TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr )
+    {
+        // Fetch node.
+        TamlCustomNode* pKeyNode = *childItr;
+
+        // Ignore anything that isn't a key.
+        if ( pKeyNode->getNodeName() != particleAssetFieldDataKeyName )
+            continue;
+
+        // Fetch the fields.
+        const TamlCustomField* pTimeField = pKeyNode->findField( particleAssetFieldDataKeyTimeName );
+        const TamlCustomField* pValueField = pKeyNode->findField( particleAssetFieldDataKeyValueName );
+
+        // Did we find the fields?
+        if ( pTimeField == NULL || pValueField == NULL )
+        {
+            // No, so warn.
+            Con::warnf("ParticleAssetField::onTamlCustomRead() - Found a key but it did not have a time and value field." );
+
+            continue;
+        }
+
+        // Read key.
+        DataKey key;
+        pTimeField->getFieldValue( key.mTime );
+        pValueField->getFieldValue( key.mValue );
+        keys.push_back( key );
+    }
+
     // Set the value bounds.
     setValueBounds( maxTime, minValue, maxValue, defaultValue );
 
@@ -662,9 +701,5 @@ void ParticleAssetField::onTamlCustomRead( const TamlPropertyAlias* pPropertyAli
     setRepeatTime( repeatTime );
 
     // Set the data keys.
-    for ( S32 index = 0; index < keys.size(); ++index )
-    {
-        const DataKey& key = keys[index];
-        addDataKey( key.mTime, key.mValue );
-    }
+    mDataKeys = keys;
 }

+ 2 - 2
engine/source/2d/assets/ParticleAssetField.h

@@ -109,8 +109,8 @@ public:
     static F32 calculateFieldBVE( const ParticleAssetField& base, const ParticleAssetField& variation, const ParticleAssetField& effect, const F32 effectAge, const bool modulate = false, const F32 modulo = 0.0f );
     static F32 calculateFieldBVLE( const ParticleAssetField& base, const ParticleAssetField& variation, const ParticleAssetField& overlife, const ParticleAssetField& effect, const F32 effectTime, const F32 particleAge, const bool modulate = false, const F32 modulo = 0.0f );
 
-    void onTamlCustomWrite( TamlCustomProperty* pCustomProperty  );
-    void onTamlCustomRead( const TamlPropertyAlias* pPropertyAlias );
+    void onTamlCustomWrite( TamlCustomNode* pCustomNode  );
+    void onTamlCustomRead( const TamlCustomNode* pCustomNode );
 };
 
 //-----------------------------------------------------------------------------

+ 22 - 19
engine/source/2d/assets/ParticleAssetFieldCollection.cc

@@ -24,7 +24,7 @@
 
 //-----------------------------------------------------------------------------
 
-static StringTableEntry particleAssetFieldCollectionName;
+static StringTableEntry particleAssetFieldNodeName;
 
 //-----------------------------------------------------------------------------
 
@@ -32,7 +32,7 @@ ParticleAssetFieldCollection::ParticleAssetFieldCollection() :
                                     mpSelectedField( NULL )
 {
     // Set custom property name.
-    particleAssetFieldCollectionName = StringTable->insert("Fields");
+    particleAssetFieldNodeName = StringTable->insert("Fields");
 }
 
 //-----------------------------------------------------------------------------
@@ -422,7 +422,7 @@ F32 ParticleAssetFieldCollection::getValueScale( void ) const
 
 //------------------------------------------------------------------------------
 
-void ParticleAssetFieldCollection::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void ParticleAssetFieldCollection::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAssetFieldCollection_OnTamlCustomWrite);
@@ -431,52 +431,55 @@ void ParticleAssetFieldCollection::onTamlCustomWrite( TamlCustomProperties& cust
     if ( mFields.size() == 0 )
         return;
 
-    // Add particle asset custom property.
-    TamlCustomProperty* pParticleAssetCustomProperty = customProperties.addProperty( particleAssetFieldCollectionName );
+    // Add particle asset custom node.
+    TamlCustomNode* pParticleAssetCustomNode = customNodes.addNode( particleAssetFieldNodeName );
 
     // Iterate the fields.
     for( typeFieldHash::iterator fieldItr = mFields.begin(); fieldItr != mFields.end(); ++fieldItr )
     {
-        fieldItr->value->onTamlCustomWrite( pParticleAssetCustomProperty );
+        fieldItr->value->onTamlCustomWrite( pParticleAssetCustomNode );
     }
 }
 
 //-----------------------------------------------------------------------------
 
-void ParticleAssetFieldCollection::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void ParticleAssetFieldCollection::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(ParticleAssetFieldCollection_OnTamlCustomRead);
 
-    // Find the particle asset custom property.
-    const TamlCustomProperty* pParticleAssetCustomProperty = customProperties.findProperty( particleAssetFieldCollectionName );
+    // Find the particle asset custom node.
+    const TamlCustomNode* pParticleAssetCustomNode = customNodes.findNode( particleAssetFieldNodeName );
 
-    // Finish if we don't have a custom property.
-    if ( pParticleAssetCustomProperty == NULL )
+    // Finish if we don't have a custom node.
+    if ( pParticleAssetCustomNode == NULL )
         return;
 
+    // Fetch children.
+    const TamlCustomNodeVector& children = pParticleAssetCustomNode->getChildren();
+
     // Iterate the custom properties.
-    for( TamlCustomProperty::const_iterator propertyAliasItr = pParticleAssetCustomProperty->begin(); propertyAliasItr != pParticleAssetCustomProperty->end(); ++propertyAliasItr )
+    for( TamlCustomNodeVector::const_iterator childNodeItr = children.begin(); childNodeItr != children.end(); ++childNodeItr )
     {
-        // Fetch property alias.
-        TamlPropertyAlias* pPropertyAlias = *propertyAliasItr;
+        // Fetch child node.
+        TamlCustomNode* pChildNode = *childNodeItr;
 
-        // Fetch alias name.
-        StringTableEntry aliasName = pPropertyAlias->mAliasName;
+        // Fetch node name.
+        StringTableEntry nodeName = pChildNode->getNodeName();
 
         // Find the field.
-        ParticleAssetField* pParticleAssetField = findField( aliasName );
+        ParticleAssetField* pParticleAssetField = findField( nodeName );
 
         // Did we find the field?
         if ( pParticleAssetField == NULL )
         {
             // No, so warn.
-            Con::warnf( "ParticleAssetFieldCollection::onTamlCustomRead() - Cannot find data field '%s'.", aliasName );
+            Con::warnf( "ParticleAssetFieldCollection::onTamlCustomRead() - Cannot find data field '%s'.", nodeName );
             continue;
         }
 
         // Read the alias.
-        pParticleAssetField->onTamlCustomRead( pPropertyAlias );
+        pParticleAssetField->onTamlCustomRead( pChildNode );
     }
 }
 

+ 2 - 2
engine/source/2d/assets/ParticleAssetFieldCollection.h

@@ -81,8 +81,8 @@ public:
     bool setValueScale( const F32 valueScale );
     F32 getValueScale( void ) const;    
 
-    void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    void onTamlCustomRead( const TamlCustomNodes& customNodes );
 };
 
 #endif // ParticleAssetFieldCollection

+ 18 - 15
engine/source/2d/core/SpriteBatch.cc

@@ -1160,7 +1160,7 @@ void SpriteBatch::destroySpriteBatchTree( void )
 
 //------------------------------------------------------------------------------
 
-void SpriteBatch::onTamlCustomWrite( TamlCustomProperty* pSpritesProperty )
+void SpriteBatch::onTamlCustomWrite( TamlCustomNode* pSpritesNode )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomWrite);
@@ -1171,38 +1171,41 @@ void SpriteBatch::onTamlCustomWrite( TamlCustomProperty* pSpritesProperty )
     // Write all sprites.
     for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
     {
-        // Add alias.
-        TamlPropertyAlias* pSpriteAlias = pSpritesProperty->addAlias( spriteItemTypeName );
+        // Add sprite node.
+        TamlCustomNode* pNode = pSpritesNode->addNode( spriteItemTypeName );
         
         // Write type with sprite item.
-        spriteItr->value->onTamlCustomWrite( pSpriteAlias );
+        spriteItr->value->onTamlCustomWrite( pNode );
     }
 }
 
 //------------------------------------------------------------------------------
 
-void SpriteBatch::onTamlCustomRead( const TamlCustomProperty* pSpritesProperty )
+void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomRead);
 
-    // Fetch property names.
-    StringTableEntry spriteItemTypeName = StringTable->insert( "Sprite" );
+    // Fetch node name.
+    StringTableEntry spriteItemNodeName = StringTable->insert( "Sprite" );
+
+    // Fetch children nodes.
+    const TamlCustomNodeVector& spriteNodes = pSpritesNode->getChildren();
 
     // Iterate sprite item types.
-    for( TamlCustomProperty::const_iterator spriteAliasItr = pSpritesProperty->begin(); spriteAliasItr != pSpritesProperty->end(); ++spriteAliasItr )
+    for( TamlCustomNodeVector::const_iterator spriteItr = spriteNodes.begin(); spriteItr != spriteNodes.end(); ++spriteItr )
     {
-        // Fetch sprite alias.
-        TamlPropertyAlias* pSpriteAlias = *spriteAliasItr;
+        // Fetch sprite node.
+        TamlCustomNode* pNode = *spriteItr;
 
         // Fetch alias name.
-        StringTableEntry aliasName = pSpriteAlias->mAliasName;
+        StringTableEntry nodeName = pNode->getNodeName();
 
-        // Is this a known alias?
-        if ( aliasName != spriteItemTypeName )
+        // Is this a known node name?
+        if ( nodeName != spriteItemNodeName )
         {
             // No, so warn.
-            Con::warnf( "SpriteBatch - Unknown custom type '%s'.", aliasName );
+            Con::warnf( "SpriteBatch - Unknown custom type '%s'.", nodeName );
             continue;
         }
 
@@ -1210,7 +1213,7 @@ void SpriteBatch::onTamlCustomRead( const TamlCustomProperty* pSpritesProperty )
         SpriteBatchItem* pSpriteBatchItem = createSprite();
 
         // Read type with sprite item.
-        pSpriteBatchItem->onTamlCustomRead( pSpriteAlias );
+        pSpriteBatchItem->onTamlCustomRead( pNode );
 
         // Fetch logical position.
         const SpriteBatchItem::LogicalPosition& logicalPosition = pSpriteBatchItem->getLogicalPosition();

+ 2 - 2
engine/source/2d/core/SpriteBatch.h

@@ -209,8 +209,8 @@ protected:
     void createSpriteBatchTree( void );
     void destroySpriteBatchTree( void );
 
-    void onTamlCustomWrite( TamlCustomProperty* pSpritesProperty );
-    void onTamlCustomRead( const TamlCustomProperty* pSpritesProperty );
+    void onTamlCustomWrite( TamlCustomNode* pSpritesNode );
+    void onTamlCustomRead( const TamlCustomNode* pSpritesNode );
 
 private:
     bool destroySprite( const U32 batchId );

+ 34 - 28
engine/source/2d/core/SpriteBatchItem.cc

@@ -332,11 +332,11 @@ void SpriteBatchItem::updateWorldTransform( const U32 batchTransformId )
 
 //------------------------------------------------------------------------------
 
-void SpriteBatchItem::onTamlCustomWrite( TamlPropertyAlias* pSpriteAlias )
+void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pSpriteNode )
 {
     // Write name.
     if ( getName() != StringTable->EmptyString )
-        pSpriteAlias->addField( spriteNameName, getName() );
+        pSpriteNode->addField( spriteNameName, getName() );
 
     // Write asset.
     if ( isStaticMode() )
@@ -348,10 +348,10 @@ void SpriteBatchItem::onTamlCustomWrite( TamlPropertyAlias* pSpriteAlias )
         if ( assetId != StringTable->EmptyString )
         {
             // Yes, so write image asset Id.
-            pSpriteAlias->addField( spriteImageName, assetId );
+            pSpriteNode->addField( spriteImageName, assetId );
 
             // Write image frame.
-            pSpriteAlias->addField( spriteImageFrameName, getImageFrame() );
+            pSpriteNode->addField( spriteImageFrameName, getImageFrame() );
         }
     }
     else
@@ -363,86 +363,89 @@ void SpriteBatchItem::onTamlCustomWrite( TamlPropertyAlias* pSpriteAlias )
         if ( assetId != StringTable->EmptyString )
         {
             // Yes, so write animation asset Id.
-            pSpriteAlias->addField( spriteAnimationName, assetId );
+            pSpriteNode->addField( spriteAnimationName, assetId );
 
         }
     }
 
     // Write visible.
     if ( !mVisible )
-        pSpriteAlias->addField( spriteVisibleName, mVisible );
+        pSpriteNode->addField( spriteVisibleName, mVisible );
 
     // Write local position.
-    pSpriteAlias->addField( spriteLocalPositionName, mLocalPosition );
+    pSpriteNode->addField( spriteLocalPositionName, mLocalPosition );
 
     // Write local angle.
     if ( mNotZero(mLocalAngle) )
-        pSpriteAlias->addField( spriteLocalAngleName, mRadToDeg(mLocalAngle) );
+        pSpriteNode->addField( spriteLocalAngleName, mRadToDeg(mLocalAngle) );
 
     // Write size.
-    pSpriteAlias->addField( spriteSizeName, mSize );
+    pSpriteNode->addField( spriteSizeName, mSize );
 
     // Write depth.
     if ( mNotZero(mDepth) )
-        pSpriteAlias->addField( spriteDepthName, mDepth );
+        pSpriteNode->addField( spriteDepthName, mDepth );
 
     // Write flipX
     if ( mFlipX )
-        pSpriteAlias->addField( spriteFlipXName, mFlipX );
+        pSpriteNode->addField( spriteFlipXName, mFlipX );
 
     // Write flipY
     if ( mFlipY )
-        pSpriteAlias->addField( spriteFlipYName, mFlipY );
+        pSpriteNode->addField( spriteFlipYName, mFlipY );
 
     // Write sort point.
     if ( mSortPoint.notZero() )
-        pSpriteAlias->addField( spriteSortPointName, mSortPoint );
+        pSpriteNode->addField( spriteSortPointName, mSortPoint );
 
     // Write render group.
     if ( mRenderGroup != StringTable->EmptyString )
-        pSpriteAlias->addField( spriteRenderGroupName, mRenderGroup );
+        pSpriteNode->addField( spriteRenderGroupName, mRenderGroup );
 
     // Write blend mode.
     if ( !mBlendMode )
-        pSpriteAlias->addField( spriteBlendModeName, mBlendMode );
+        pSpriteNode->addField( spriteBlendModeName, mBlendMode );
 
     // Write source blend factor.
     if ( mBlendMode && mSrcBlendFactor != GL_SRC_ALPHA )
-        pSpriteAlias->addField( spriteBlendModeName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
+        pSpriteNode->addField( spriteBlendModeName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
         
     // Write destination blend factor.
     if ( mBlendMode && mDstBlendFactor != GL_ONE_MINUS_SRC_ALPHA )
-        pSpriteAlias->addField( spriteDstBlendFactorName, SceneObject::getDstBlendFactorDescription(mDstBlendFactor) );
+        pSpriteNode->addField( spriteDstBlendFactorName, SceneObject::getDstBlendFactorDescription(mDstBlendFactor) );
 
     // Write blend color.
     if ( mBlendMode && mBlendColor != ColorF(1.0f, 1.0f, 1.0f, 1.0f) )
-        pSpriteAlias->addField( spriteBlendColorName, mBlendColor );
+        pSpriteNode->addField( spriteBlendColorName, mBlendColor );
 
     // Write alpha test.
     if ( mBlendMode && mAlphaTest >= 0.0f )
-        pSpriteAlias->addField( spriteAlphaTestName, mAlphaTest );
+        pSpriteNode->addField( spriteAlphaTestName, mAlphaTest );
 
     // Write logical position.
     if ( getLogicalPosition().isValid() )
-        pSpriteAlias->addField( spriteLogicalPositionName, getLogicalPosition().getString() );
+        pSpriteNode->addField( spriteLogicalPositionName, getLogicalPosition().getString() );
 
     // Write data object.
     if ( getDataObject() != NULL )
-        pSpriteAlias->addField( spriteDataObjectName, getDataObject() );
+        pSpriteNode->addNode( getDataObject() );
 }
 
 //------------------------------------------------------------------------------
 
-void SpriteBatchItem::onTamlCustomRead( const TamlPropertyAlias* pSpriteAlias )
+void SpriteBatchItem::onTamlCustomRead( const TamlCustomNode* pSpriteNode )
 {
     // Sanity!
     AssertFatal( mSpriteBatch != NULL, "SpriteBatchItem::onTamlCustomRead() - Cannot read sprite batch item with sprite batch." );
 
+    // Fetch sprite fields.
+    const TamlCustomFieldVector& spriteField = pSpriteNode->getFields();
+
     // Iterate property fields.
-    for ( TamlPropertyAlias::const_iterator propertyFieldItr = pSpriteAlias->begin(); propertyFieldItr != pSpriteAlias->end(); ++propertyFieldItr )
+    for ( TamlCustomFieldVector::const_iterator fieldItr = spriteField.begin(); fieldItr != spriteField.end(); ++fieldItr )
     {
         // Fetch sprite field.
-        TamlPropertyField* pSpriteField = *propertyFieldItr;
+        TamlCustomField* pSpriteField = *fieldItr;
 
         // Fetch sprite field name.
         StringTableEntry fieldName = pSpriteField->getFieldName();
@@ -570,9 +573,12 @@ void SpriteBatchItem::onTamlCustomRead( const TamlPropertyAlias* pSpriteAlias )
             // Set logical position.
             setLogicalPosition( LogicalPosition( pLogicalPositionArgs ) );
         }
-        else if ( fieldName == spriteDataObjectName )
-        {            
-            setDataObject( pSpriteField->getFieldObject() );
-        }
     }
+
+    // Fetch sprite children.
+    const TamlCustomNodeVector& spriteChildren = pSpriteNode->getChildren();
+
+    // Set the data object if a single child exists.
+    if ( spriteChildren.size() == 1 )
+        setDataObject( spriteChildren[0]->getProxyObject<SimObject>(true) );
 }

+ 2 - 2
engine/source/2d/core/SpriteBatchItem.h

@@ -294,8 +294,8 @@ protected:
     void updateLocalTransform( void );
     void updateWorldTransform( const U32 batchTransformId );
 
-    void onTamlCustomWrite( TamlPropertyAlias* pSpriteAlias );
-    void onTamlCustomRead( const TamlPropertyAlias* pSpriteAlias );
+    void onTamlCustomWrite( TamlCustomNode* pSpriteNode );
+    void onTamlCustomRead( const TamlCustomNode* pSpriteNode );
 };
 
 //------------------------------------------------------------------------------  

File diff suppressed because it is too large
+ 733 - 606
engine/source/2d/scene/Scene.cc


+ 3 - 3
engine/source/2d/scene/Scene.h

@@ -291,9 +291,9 @@ private:
 protected:
     /// Taml callbacks.
     virtual void            onTamlPreRead( void );
-    virtual void            onTamlPostRead( const TamlCustomProperties& customProperties );
-    virtual void            onTamlCustomWrite( TamlCustomProperties& customProperties );
-    virtual void            onTamlCustomRead( const TamlCustomProperties& customProperties );
+    virtual void            onTamlPostRead( const TamlCustomNodes& customNodes );
+    virtual void            onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void            onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 public:
     Scene();

+ 14 - 14
engine/source/2d/sceneobject/CompositeSprite.cc

@@ -381,10 +381,10 @@ SpriteBatchItem* CompositeSprite::createCustomLayout( const SpriteBatchItem::Log
 
 //-----------------------------------------------------------------------------
 
-void CompositeSprite::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void CompositeSprite::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomWrite( customProperties );
+    Parent::onTamlCustomWrite( customNodes );
 
     // Fetch sprite count.
     const U32 spriteCount = getSpriteCount();
@@ -393,27 +393,27 @@ void CompositeSprite::onTamlCustomWrite( TamlCustomProperties& customProperties
     if ( spriteCount == 0 )
         return;
 
-    // Add sprites property.
-    TamlCustomProperty* pSpritesProperty = customProperties.addProperty( StringTable->insert("Sprites") );
+    // Add sprites node.
+    TamlCustomNode* pSpritesNode = customNodes.addNode( StringTable->insert("Sprites") );
 
-    // Write property with sprite batch.
-    SpriteBatch::onTamlCustomWrite( pSpritesProperty );
+    // Write node with sprite batch.
+    SpriteBatch::onTamlCustomWrite( pSpritesNode );
 }
 
 //-----------------------------------------------------------------------------
 
-void CompositeSprite::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void CompositeSprite::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomRead( customProperties );
+    Parent::onTamlCustomRead( customNodes );
 
-    // Find sprites custom property.
-    const TamlCustomProperty* pSpritesProperty = customProperties.findProperty( StringTable->insert("Sprites") );
+    // Find sprites custom node.
+    const TamlCustomNode* pSpritesNode = customNodes.findNode( StringTable->insert("Sprites") );
 
-    // Finish if we don't have the property.
-    if ( pSpritesProperty == NULL )
+    // Finish if we don't have the node.
+    if ( pSpritesNode == NULL )
         return;
 
-    // Read property with sprite batch.
-    SpriteBatch::onTamlCustomRead( pSpritesProperty );
+    // Read node with sprite batch.
+    SpriteBatch::onTamlCustomRead( pSpritesNode );
 }

+ 2 - 2
engine/source/2d/sceneobject/CompositeSprite.h

@@ -85,8 +85,8 @@ protected:
     virtual SpriteBatchItem* createSpriteIsometricLayout( const SpriteBatchItem::LogicalPosition& logicalPosition );
     virtual SpriteBatchItem* createCustomLayout( const SpriteBatchItem::LogicalPosition& logicalPosition );
 
-    virtual void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    virtual void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 protected:
     static bool         setDefaultSpriteAngle(void* obj, const char* data)                  { STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->setDefaultSpriteAngle(mDegToRad(dAtof(data))); return false; }

+ 276 - 171
engine/source/2d/sceneobject/SceneObject.cc

@@ -87,30 +87,22 @@ static U32 sSceneObjectMasterSerialId = 0;
 // Collision shape property names.
 static bool collisionShapePropertiesInitialized = false;
 
-static StringTableEntry shapeCustomPropertyName;
+static StringTableEntry shapeCustomNodeName;
 
 static StringTableEntry shapeDensityName;
 static StringTableEntry shapeFrictionName;
 static StringTableEntry shapeRestitutionName;
 static StringTableEntry shapeSensorName;
+static StringTableEntry shapePointName;
+static StringTableEntry shapePrevPointName;
+static StringTableEntry shapeNextPointName;
 
 static StringTableEntry circleTypeName;
 static StringTableEntry circleRadiusName;
 static StringTableEntry circleOffsetName;
-
 static StringTableEntry polygonTypeName;
-static StringTableEntry polygonPointName;
-
 static StringTableEntry chainTypeName;
-static StringTableEntry chainPointName;
-static StringTableEntry chainAdjacentStartName;
-static StringTableEntry chainAdjacentEndName;
-
 static StringTableEntry edgeTypeName;
-static StringTableEntry edgeStartName;
-static StringTableEntry edgeEndName;
-static StringTableEntry edgeAdjacentStartName;
-static StringTableEntry edgeAdjacentEndName;
 
 //------------------------------------------------------------------------------
 
@@ -208,30 +200,21 @@ SceneObject::SceneObject() :
     // Initialize collision shape field names.
     if ( !collisionShapePropertiesInitialized )
     {
-        shapeCustomPropertyName     = StringTable->insert( "CollisionShapes" );
+        shapeCustomNodeName     = StringTable->insert( "CollisionShapes" );
 
         shapeDensityName        = StringTable->insert( "Density" );
         shapeFrictionName       = StringTable->insert( "Friction" );
         shapeRestitutionName    = StringTable->insert( "Restitution" );
         shapeSensorName         = StringTable->insert( "Sensor" );
-
+        shapePointName          = StringTable->insert( "Point" );
+        shapePrevPointName      = StringTable->insert( "PreviousPoint" );
+        shapeNextPointName      = StringTable->insert( "NextPoint" );
         circleTypeName          = StringTable->insert( "Circle" );
         circleRadiusName        = StringTable->insert( "Radius" );
         circleOffsetName        = StringTable->insert( "Offset" );
-
         polygonTypeName         = StringTable->insert( "Polygon" );
-        polygonPointName        = StringTable->insert( "Point" );
-
         chainTypeName           = StringTable->insert( "Chain" );
-        chainPointName          = polygonPointName;
-        chainAdjacentStartName  = StringTable->insert( "AdjacentStartPoint" );
-        chainAdjacentEndName    = StringTable->insert( "AdjacentEndPoint" );
-
         edgeTypeName            = StringTable->insert( "Edge" );
-        edgeStartName           = StringTable->insert( "Point0" );
-        edgeEndName             = StringTable->insert( "Point1" );
-        edgeAdjacentStartName   = chainAdjacentStartName;
-        edgeAdjacentEndName     = chainAdjacentEndName;
 
         // Flag as initialized.
         collisionShapePropertiesInitialized = true;
@@ -3371,13 +3354,13 @@ U32 SceneObject::getGlobalSceneObjectCount( void )
 
 //-----------------------------------------------------------------------------
 
-void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void SceneObject::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SceneObject_OnTamlCustomWrite);
 
     // Call parent.
-    Parent::onTamlCustomWrite( customProperties );
+    Parent::onTamlCustomWrite( customNodes );
 
     // Fetch collision shape count.
     const U32 collisionShapeCount = getCollisionShapeCount();
@@ -3386,8 +3369,8 @@ void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
     if ( collisionShapeCount == 0 )
         return;
 
-    // Add collision shape property.
-    TamlCustomProperty* pCollisionShapeProperty = customProperties.addProperty( shapeCustomPropertyName );
+    // Add collision shape node.
+    TamlCustomNode* pCustomCollisionShapes = customNodes.addNode( shapeCustomNodeName );
 
     // Iterate collision shapes.
     for ( U32 shapeIndex = 0; shapeIndex < collisionShapeCount; ++shapeIndex )
@@ -3395,30 +3378,30 @@ void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
         // Fetch collision shape definition.
         b2FixtureDef fixtureDef = getCollisionShapeDefinition( shapeIndex );
 
-        // Add collision shape alias.
-        // NOTE:    The name of the alias will get updated shortly.
-        TamlPropertyAlias* pCollisionShapeAlias = pCollisionShapeProperty->addAlias( StringTable->EmptyString );
+        // Add collision shape node.
+        // NOTE:    The name of the node will get updated shortly.
+        TamlCustomNode* pCollisionShapeNode = pCustomCollisionShapes->addNode( StringTable->EmptyString );
 
         // Add common collision shape fields.
         if ( mNotEqual( getDefaultDensity(), fixtureDef.density ) )
-            pCollisionShapeAlias->addField( shapeDensityName, fixtureDef.density );
+            pCollisionShapeNode->addField( shapeDensityName, fixtureDef.density );
 
         if ( mNotEqual( getDefaultFriction(), fixtureDef.friction ) )
-            pCollisionShapeAlias->addField( shapeFrictionName, fixtureDef.friction );
+            pCollisionShapeNode->addField( shapeFrictionName, fixtureDef.friction );
 
         if ( mNotEqual( getDefaultRestitution(), fixtureDef.restitution ) )
-            pCollisionShapeAlias->addField( shapeRestitutionName, fixtureDef.restitution );
+            pCollisionShapeNode->addField( shapeRestitutionName, fixtureDef.restitution );
 
         if ( fixtureDef.isSensor == true )
-            pCollisionShapeAlias->addField( shapeSensorName, fixtureDef.isSensor );
+            pCollisionShapeNode->addField( shapeSensorName, fixtureDef.isSensor );
 
         // Populate collision shape appropriately.
         switch( fixtureDef.shape->GetType() )
         {
         case b2Shape::e_circle:
             {
-                // Set alias name.
-                pCollisionShapeAlias->mAliasName = StringTable->insert( circleTypeName );
+                // Set node name.
+                pCollisionShapeNode->setNodeName( circleTypeName );
 
                 // Fetch shape.
                 const b2CircleShape* pShape = dynamic_cast<const b2CircleShape*>( fixtureDef.shape );
@@ -3427,18 +3410,18 @@ void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
                 AssertFatal( pShape != NULL, "SceneObject::onTamlCustomWrite() - Invalid circle shape type returned." );
 
                 // Add radius property.
-                pCollisionShapeAlias->addField( circleRadiusName, pShape->m_radius );
+                pCollisionShapeNode->addField( circleRadiusName, pShape->m_radius );
 
                 // Add offset property (if not zero).
                 if ( !Vector2(pShape->m_p).isZero() )
-                    pCollisionShapeAlias->addField( circleOffsetName, pShape->m_p );
+                    pCollisionShapeNode->addField( circleOffsetName, pShape->m_p );
             }
             break;
 
         case b2Shape::e_polygon:
             {
-                // Set alias name.
-                pCollisionShapeAlias->mAliasName = StringTable->insert( polygonTypeName );
+                // Set node name.
+                pCollisionShapeNode->setNodeName( polygonTypeName );
 
                 // Fetch shape.
                 const b2PolygonShape* pShape = dynamic_cast<const b2PolygonShape*>( fixtureDef.shape );
@@ -3452,20 +3435,22 @@ void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
                 // Add shape properties.
                 for ( U32 pointIndex = 0; pointIndex < pointCount; ++pointIndex )
                 {
-                    // Format point index name.
-                    char pointIndexBuffer[16];
-                    dSprintf( pointIndexBuffer, sizeof(pointIndexBuffer), "%s%d", polygonPointName, pointIndex );
-                    
-                    // Add point property.
-                    pCollisionShapeAlias->addField( pointIndexBuffer, pShape->GetVertex( pointIndex ) );
+                    // Add point node.
+                    TamlCustomNode* pPointNode = pCollisionShapeNode->addNode( shapePointName );
+
+                    // Fetch point.
+                    const b2Vec2& point = pShape->GetVertex( pointIndex );
+
+                    // Add point fields.
+                    pPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, point );
                 }
             }
             break;
 
         case b2Shape::e_chain:
             {
-                // Set alias name.
-                pCollisionShapeAlias->mAliasName = StringTable->insert( chainTypeName );
+                // Set node name.
+                pCollisionShapeNode->setNodeName( chainTypeName );
 
                 // Fetch shape.
                 const b2ChainShape* pShape = dynamic_cast<const b2ChainShape*>( fixtureDef.shape );
@@ -3479,28 +3464,33 @@ void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
                 // Add shape properties.
                 for ( U32 pointIndex = 0; pointIndex < pointCount; ++pointIndex )
                 {
-                    // Format point index name.
-                    char pointIndexBuffer[16];
-                    dSprintf( pointIndexBuffer, sizeof(pointIndexBuffer), "%s%d", chainPointName, pointIndex );
-                    
-                    // Add point property.
-                    pCollisionShapeAlias->addField( pointIndexBuffer, pShape->m_vertices[pointIndex] );
+                    // Add point node.
+                    TamlCustomNode* pPointNode = pCollisionShapeNode->addNode( shapePointName );
+
+                    // Add point fields.
+                    pPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, pShape->m_vertices[pointIndex] );
                 }
 
                 // Add adjacent start point (if specified).
                 if ( pShape->m_hasPrevVertex )
-                    pCollisionShapeAlias->addField( chainAdjacentStartName, pShape->m_prevVertex );
+                {
+                    TamlCustomNode* pPrevPointNode = pCollisionShapeNode->addNode( shapePrevPointName );
+                    pPrevPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, pShape->m_prevVertex );
+                }
 
                 // Add adjacent end point (if specified).
                 if ( pShape->m_hasNextVertex )
-                    pCollisionShapeAlias->addField( chainAdjacentEndName, pShape->m_nextVertex );
+                {
+                    TamlCustomNode* pNextPointNode = pCollisionShapeNode->addNode( shapeNextPointName );
+                    pNextPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, pShape->m_nextVertex );
+                }
             }
             break;
 
         case b2Shape::e_edge:
             {
-                // Set alias name.
-                pCollisionShapeAlias->mAliasName = StringTable->insert( edgeTypeName );
+                // Set node name.
+                pCollisionShapeNode->setNodeName( edgeTypeName );
 
                 // Fetch shape.
                 const b2EdgeShape* pShape = dynamic_cast<const b2EdgeShape*>( fixtureDef.shape );
@@ -3508,17 +3498,27 @@ void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
                 // Sanity!
                 AssertFatal( pShape != NULL, "SceneObject::onTamlCustomWrite() - Invalid edge shape type returned." );
 
-                // Add start/end points.
-                pCollisionShapeAlias->addField( edgeStartName, pShape->m_vertex1 );
-                pCollisionShapeAlias->addField( edgeEndName, pShape->m_vertex2 );
+                // Add start point.
+                TamlCustomNode* pStartPointNode = pCollisionShapeNode->addNode( shapePointName );
+                pStartPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, pShape->m_vertex1 );
+
+                // Add end point.
+                TamlCustomNode* pEndPointNode = pCollisionShapeNode->addNode( shapePointName );
+                pEndPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, pShape->m_vertex2 );
 
                 // Add adjacent start point (if specified).
                 if ( pShape->m_hasVertex0 )
-                    pCollisionShapeAlias->addField( edgeAdjacentStartName, pShape->m_vertex0 );
+                {
+                    TamlCustomNode* pPrevPointNode = pCollisionShapeNode->addNode( shapePrevPointName );
+                    pPrevPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, pShape->m_vertex0 );
+                }
 
                 // Add adjacent end point (if specified).
                 if ( pShape->m_hasVertex3 )
-                    pCollisionShapeAlias->addField( edgeAdjacentEndName, pShape->m_vertex3 );
+                {
+                    TamlCustomNode* pNextPointNode = pCollisionShapeNode->addNode( shapeNextPointName );
+                    pNextPointNode->getNodeTextField().setFieldValue( StringTable->EmptyString, pShape->m_vertex3 );
+                }
             }
             break;
 
@@ -3531,29 +3531,32 @@ void SceneObject::onTamlCustomWrite( TamlCustomProperties& customProperties )
 
 //-----------------------------------------------------------------------------
 
-void SceneObject::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void SceneObject::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SceneObject_OnTamlCustomRead);
 
     // Call parent.
-    Parent::onTamlCustomRead( customProperties );
+    Parent::onTamlCustomRead( customNodes );
 
-    // Find collision shape custom property.
-    const TamlCustomProperty* pCollisionShapeProperty = customProperties.findProperty( shapeCustomPropertyName );
+    // Find collision shape custom node.
+    const TamlCustomNode* pCustomCollisionShapes = customNodes.findNode( shapeCustomNodeName );
 
     // Finish if we don't have collision shapes.
-    if ( pCollisionShapeProperty == NULL )
+    if ( pCustomCollisionShapes == NULL )
         return;
 
+    // Fetch children shapes.
+    const TamlCustomNodeVector& collisionShapeChildren = pCustomCollisionShapes->getChildren();
+
     // Iterate collision shapes.
-    for( TamlCustomProperty::const_iterator propertyAliasItr = pCollisionShapeProperty->begin(); propertyAliasItr != pCollisionShapeProperty->end(); ++propertyAliasItr )
+    for( TamlCustomNodeVector::const_iterator shapeNodeItr = collisionShapeChildren.begin(); shapeNodeItr != collisionShapeChildren.end(); ++shapeNodeItr )
     {
-        // Fetch property alias.
-        TamlPropertyAlias* pPropertyAlias = *propertyAliasItr;
+        // Fetch shape node.
+        TamlCustomNode* pShapeNode = *shapeNodeItr;
 
-        // Fetch alias name.
-        StringTableEntry aliasName = pPropertyAlias->mAliasName;
+        // Fetch shape name.
+        StringTableEntry shapeName = pShapeNode->getNodeName();
 
         // Ready common fields.
         F32 shapeDensity     = getDefaultDensity();
@@ -3564,46 +3567,49 @@ void SceneObject::onTamlCustomRead( const TamlCustomProperties& customProperties
         S32 shapeIndex;
 
         // Is this a circle shape?
-        if ( aliasName == circleTypeName )
+        if ( shapeName == circleTypeName )
         {
             // Yes, so ready fields.
             F32 radius = 0.0f;
             b2Vec2 offset( 0.0f, 0.0f );
 
+            // Fetch shape children.
+            const TamlCustomFieldVector& shapeFields = pShapeNode->getFields();
+
             // Iterate property fields.
-            for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
+            for ( TamlCustomFieldVector::const_iterator shapeFieldItr = shapeFields.begin(); shapeFieldItr != shapeFields.end(); ++shapeFieldItr )
             {
-                // Fetch property field.
-                TamlPropertyField* pPropertyField = *propertyFieldItr;
+                // Fetch field.
+                const TamlCustomField* pField = *shapeFieldItr;
 
                 // Fetch property field name.
-                StringTableEntry fieldName = pPropertyField->getFieldName();
+                StringTableEntry fieldName = pField->getFieldName();
 
                 // Check common fields.
                 if ( fieldName == shapeDensityName )
                 {
-                    pPropertyField->getFieldValue( shapeDensity );
+                    pField->getFieldValue( shapeDensity );
                 }
                 else if ( fieldName == shapeFrictionName )
                 {
-                    pPropertyField->getFieldValue( shapeFriction );
+                    pField->getFieldValue( shapeFriction );
                 }
                 else if ( fieldName == shapeRestitutionName )
                 {
-                    pPropertyField->getFieldValue( shapeRestitution );
+                    pField->getFieldValue( shapeRestitution );
                 }
                 else if ( fieldName == shapeSensorName )
                 {
-                    pPropertyField->getFieldValue( shapeSensor );
+                    pField->getFieldValue( shapeSensor );
                 }
                 // Check circle fields.
                 else if ( fieldName == circleRadiusName )
                 {
-                    pPropertyField->getFieldValue( radius );
+                    pField->getFieldValue( radius );
                 }
                 else if ( fieldName == circleOffsetName )
                 {
-                    pPropertyField->getFieldValue( offset );
+                    pField->getFieldValue( offset );
                 }                   
             }
 
@@ -3621,51 +3627,68 @@ void SceneObject::onTamlCustomRead( const TamlCustomProperties& customProperties
             shapeIndex = createCircleCollisionShape( radius, offset );
         }
         // Is this a polygon shape?
-        else if ( aliasName == polygonTypeName )
+        else if ( shapeName == polygonTypeName )
         {
-            // Yes, so ready fields.
-            b2Vec2 points[b2_maxPolygonVertices];
-            U32 pointCount = 0;
+            // Yes, so fetch shape fields.
+            const TamlCustomFieldVector& shapeFields = pShapeNode->getFields();
 
             // Iterate property fields.
-            for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
+            for ( TamlCustomFieldVector::const_iterator shapeFieldItr = shapeFields.begin(); shapeFieldItr != shapeFields.end(); ++shapeFieldItr )
             {
-                // Fetch property field.
-                TamlPropertyField* pPropertyField = *propertyFieldItr;
+                // Fetch field.
+                const TamlCustomField* pField = *shapeFieldItr;
 
                 // Fetch property field name.
-                StringTableEntry fieldName = pPropertyField->getFieldName();
+                StringTableEntry fieldName = pField->getFieldName();
 
                 // Check common fields.
                 if ( fieldName == shapeDensityName )
                 {
-                    pPropertyField->getFieldValue( shapeDensity );
+                    pField->getFieldValue( shapeDensity );
                 }
                 else if ( fieldName == shapeFrictionName )
                 {
-                    pPropertyField->getFieldValue( shapeFriction );
+                    pField->getFieldValue( shapeFriction );
                 }
                 else if ( fieldName == shapeRestitutionName )
                 {
-                    pPropertyField->getFieldValue( shapeRestitution );
+                    pField->getFieldValue( shapeRestitution );
                 }
                 else if ( fieldName == shapeSensorName )
                 {
-                    pPropertyField->getFieldValue( shapeSensor );
+                    pField->getFieldValue( shapeSensor );
                 }
-                // Check polygon fields.
-                else if ( pPropertyField->fieldNameBeginsWith( polygonPointName ) )
+            }
+
+            // Fetch shape children.
+            const TamlCustomNodeVector& shapeChildren = pShapeNode->getChildren();
+
+            // Fetch shape children count.
+            const U32 shapeChildrenCount = (U32)shapeChildren.size();
+
+            // Reset points.
+            b2Vec2 points[b2_maxPolygonVertices];
+            U32 pointCount = 0;
+
+            // Do we have any shape children.
+            if ( shapeChildrenCount > 0 )
+            {
+                // Yes, so iterate them.
+                for( TamlCustomNodeVector::const_iterator childItr = shapeChildren.begin(); childItr != shapeChildren.end(); ++childItr )
                 {
-                    // Is the point count at maximum?
-                    if ( pointCount == b2_maxPolygonVertices )
-                    {
-                        // Yes, so warn.
-                        Con::warnf( "SceneObject::onTamlCustomRead() - Polygon point count exceed the maximum points '%d'.", b2_maxPolygonVertices );
+                    TamlCustomNode* pChildNode = *childItr;
+
+                    // Skip if it's not a point.
+                    if ( pChildNode->getNodeName() != shapePointName )
+                        continue;
+                    
+                    // Skip if it's empty.
+                    if ( pChildNode->getNodeTextField().isValueEmpty() )
                         continue;
-                    }
 
+                    // Read point.
                     b2Vec2 point;
-                    pPropertyField->getFieldValue( point );
+                    pChildNode->getNodeTextField().getFieldValue( point );
                     points[pointCount++] = point;
                 }
             }
@@ -3683,65 +3706,99 @@ void SceneObject::onTamlCustomRead( const TamlCustomProperties& customProperties
             shapeIndex = createPolygonCollisionShape( pointCount, points );
         }
         // Is this a chain shape?
-        else if ( aliasName == chainTypeName )
+        else if ( shapeName == chainTypeName )
         {
             // Yes, so ready fields.
             Vector<b2Vec2> points;
-            bool hasAdjacentStartPoint;
-            bool hasAdjacentEndPoint;
+            bool hasAdjacentStartPoint = false;
+            bool hasAdjacentEndPoint = false;
             b2Vec2 adjacentStartPoint;
             b2Vec2 adjacentEndPoint;
 
+            // Fetch shape children.
+            const TamlCustomFieldVector& shapeFields = pShapeNode->getFields();
+
             // Iterate property fields.
-            for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
+            for ( TamlCustomFieldVector::const_iterator shapeFieldItr = shapeFields.begin(); shapeFieldItr != shapeFields.end(); ++shapeFieldItr )
             {
-                // Fetch property field.
-                TamlPropertyField* pPropertyField = *propertyFieldItr;
+                // Fetch field.
+                const TamlCustomField* pField = *shapeFieldItr;
 
                 // Fetch property field name.
-                StringTableEntry fieldName = pPropertyField->getFieldName();
+                StringTableEntry fieldName = pField->getFieldName();
 
                 // Check common fields.
                 if ( fieldName == shapeDensityName )
                 {
-                    pPropertyField->getFieldValue( shapeDensity );
+                    pField->getFieldValue( shapeDensity );
                 }
                 else if ( fieldName == shapeFrictionName )
                 {
-                    pPropertyField->getFieldValue( shapeFriction );
+                    pField->getFieldValue( shapeFriction );
                 }
                 else if ( fieldName == shapeRestitutionName )
                 {
-                    pPropertyField->getFieldValue( shapeRestitution );
+                    pField->getFieldValue( shapeRestitution );
                 }
                 else if ( fieldName == shapeSensorName )
                 {
-                    pPropertyField->getFieldValue( shapeSensor );
-                }
-                // Check chain fields.
-                else if ( pPropertyField->fieldNameBeginsWith( chainPointName ) )
-                {
-                    b2Vec2 point;
-                    pPropertyField->getFieldValue( point );
-                    points.push_back( point );
-                }
-                else if ( fieldName == chainAdjacentStartName )
-                {
-                    pPropertyField->getFieldValue( adjacentStartPoint );
-                    hasAdjacentStartPoint = true;
+                    pField->getFieldValue( shapeSensor );
                 }
-                else if ( fieldName == chainAdjacentEndName )
+            }
+
+            // Fetch shape children.
+            const TamlCustomNodeVector& shapeChildren = pShapeNode->getChildren();
+
+            // Fetch shape children count.
+            const U32 shapeChildrenCount = (U32)shapeChildren.size();
+
+            // Do we have any shape children.
+            // NOTE: Only do this if the old methods has not been used.
+            if ( points.size() == 0 && shapeChildrenCount > 0 )
+            {
+                // Yes, so iterate them.
+                for( TamlCustomNodeVector::const_iterator childItr = shapeChildren.begin(); childItr != shapeChildren.end(); ++childItr )
                 {
-                    pPropertyField->getFieldValue( adjacentEndPoint );
-                    hasAdjacentEndPoint = true;
+                    TamlCustomNode* pChildNode = *childItr;
+
+                    // Fetch the node name.
+                    StringTableEntry nodeName = pChildNode->getNodeName();
+
+                    // Skip if it's not a point.
+                    if ( !(nodeName == shapePointName || nodeName == shapePrevPointName || nodeName == shapeNextPointName) )
+                        continue;
+                    
+                    // Skip if it's empty.
+                    if ( pChildNode->getNodeTextField().isValueEmpty() )
+                        continue;
+
+                    if ( nodeName == shapePointName )
+                    {
+                        // Read point.
+                        b2Vec2 point;
+                        pChildNode->getNodeTextField().getFieldValue( point );
+                        points.push_back( point );
+                    }
+                    else if ( nodeName == shapePrevPointName )
+                    {
+                        // Read adjacent point.
+                        pChildNode->getNodeTextField().getFieldValue( adjacentStartPoint );
+                        hasAdjacentStartPoint = true;
+                    }
+                    else if ( nodeName == shapeNextPointName )
+                    {
+                        // Read adjacent point.
+                        pChildNode->getNodeTextField().getFieldValue( adjacentEndPoint );
+                        hasAdjacentEndPoint = true;
+                    }
                 }
             }
 
             // Is point count valid?
-            if ( points.size() == 0 )
+            if ( points.size() == 0 || points.size() < 2 )
             {
                 // No, so warn.
-                Con::warnf( "SceneObject::onTamlCustomRead() - No points on chain collision shape." );
+                Con::warnf( "SceneObject::onTamlCustomRead() - No points (or less than two) on chain collision shape." );
 
                 continue;
             }
@@ -3750,63 +3807,111 @@ void SceneObject::onTamlCustomRead( const TamlCustomProperties& customProperties
             shapeIndex = createChainCollisionShape( points.size(), points.address(), hasAdjacentStartPoint, hasAdjacentEndPoint, adjacentStartPoint, adjacentEndPoint );
         }
         // Is this an edge shape?
-        else if ( aliasName == edgeTypeName )
+        else if ( shapeName == edgeTypeName )
         {
             // Yes, so ready fields.
             b2Vec2 point0;
             b2Vec2 point1;
-            bool hasAdjacentStartPoint;
-            bool hasAdjacentEndPoint;
+            U32 pointCount = 0;
+            bool hasAdjacentStartPoint = false;
+            bool hasAdjacentEndPoint = false;
             b2Vec2 adjacentStartPoint;
             b2Vec2 adjacentEndPoint;
 
+            // Fetch shape children.
+            const TamlCustomFieldVector& shapeFields = pShapeNode->getFields();
+
             // Iterate property fields.
-            for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
+            for ( TamlCustomFieldVector::const_iterator shapeFieldItr = shapeFields.begin(); shapeFieldItr != shapeFields.end(); ++shapeFieldItr )
             {
-                // Fetch property field.
-                TamlPropertyField* pPropertyField = *propertyFieldItr;
+                // Fetch field.
+                const TamlCustomField* pField = *shapeFieldItr;
 
                 // Fetch property field name.
-                StringTableEntry fieldName = pPropertyField->getFieldName();
+                StringTableEntry fieldName = pField->getFieldName();
 
                 // Check common fields.
                 if ( fieldName == shapeDensityName )
                 {
-                    pPropertyField->getFieldValue( shapeDensity );
+                    pField->getFieldValue( shapeDensity );
                 }
                 else if ( fieldName == shapeFrictionName )
                 {
-                    pPropertyField->getFieldValue( shapeFriction );
+                    pField->getFieldValue( shapeFriction );
                 }
                 else if ( fieldName == shapeRestitutionName )
                 {
-                    pPropertyField->getFieldValue( shapeRestitution );
+                    pField->getFieldValue( shapeRestitution );
                 }
                 else if ( fieldName == shapeSensorName )
                 {
-                    pPropertyField->getFieldValue( shapeSensor );
-                }
-                // Check edge fields.
-                else if ( fieldName == edgeStartName )
-                {
-                    pPropertyField->getFieldValue( point0 );
+                    pField->getFieldValue( shapeSensor );
                 }
-                else if ( fieldName == edgeEndName )
-                {
-                    pPropertyField->getFieldValue( point1 );
-                }
-                else if ( fieldName == edgeAdjacentStartName )
-                {
-                    pPropertyField->getFieldValue( adjacentStartPoint );
-                    hasAdjacentStartPoint = true;
-                }
-                else if ( fieldName == edgeAdjacentEndName )
+            }
+
+            // Fetch shape children.
+            const TamlCustomNodeVector& shapeChildren = pShapeNode->getChildren();
+
+            // Fetch shape children count.
+            const U32 shapeChildrenCount = (U32)shapeChildren.size();
+
+            // Do we have any shape children.
+            if ( shapeChildrenCount > 0 )
+            {
+                // Yes, so iterate them.
+                for( TamlCustomNodeVector::const_iterator childItr = shapeChildren.begin(); childItr != shapeChildren.end(); ++childItr )
                 {
-                    pPropertyField->getFieldValue( adjacentEndPoint );
-                    hasAdjacentEndPoint = true;
+                    TamlCustomNode* pChildNode = *childItr;
+
+                    // Fetch the node name.
+                    StringTableEntry nodeName = pChildNode->getNodeName();
+
+                    // Skip if it's not a point.
+                    if ( !(nodeName == shapePointName || nodeName == shapePrevPointName || nodeName == shapeNextPointName) )
+                        continue;
+                    
+                    // Skip if it's empty.
+                    if ( pChildNode->getNodeTextField().isValueEmpty() )
+                        continue;
+
+                    if ( nodeName == shapePointName )
+                    {
+                        // Ignore if too many points.
+                        if ( pointCount >= 2 )
+                            continue;
+
+                        // Read point.               
+                        if ( pointCount == 0 )
+                            pChildNode->getNodeTextField().getFieldValue( point0 );
+                        else
+                            pChildNode->getNodeTextField().getFieldValue( point1 );
+
+                        pointCount++;
+                    }
+                    else if ( nodeName == shapePrevPointName )
+                    {
+                        // Read adjacent point.
+                        pChildNode->getNodeTextField().getFieldValue( adjacentStartPoint );
+                        hasAdjacentStartPoint = true;
+                    }
+                    else if ( nodeName == shapeNextPointName )
+                    {
+                        // Read adjacent point.
+                        pChildNode->getNodeTextField().getFieldValue( adjacentEndPoint );
+                        hasAdjacentEndPoint = true;
+                    }
                 }
             }
 
+            // Is point count valid?
+            if ( pointCount == 0 || pointCount != 2 )
+            {
+                // No, so warn.
+                Con::warnf( "SceneObject::onTamlCustomRead() - No points (or not two points) on edge collision shape." );
+
+                continue;
+            }
+
             // Create shape.
             shapeIndex = createEdgeCollisionShape( point0, point1, hasAdjacentStartPoint, hasAdjacentEndPoint, adjacentStartPoint, adjacentEndPoint );
         }
@@ -3814,7 +3919,7 @@ void SceneObject::onTamlCustomRead( const TamlCustomProperties& customProperties
         else
         {
             // Warn.
-            Con::warnf( "Unknown shape type of '%s' encountered.", aliasName );
+            Con::warnf( "Unknown shape type of '%s' encountered.", shapeName );
 
             // Sanity!
             AssertFatal( false, "SceneObject::onTamlCustomRead() - Unknown shape type detected." );
@@ -3873,9 +3978,9 @@ S32 QSORT_CALLBACK SceneObject::sceneObjectLayerDepthSort(const void* a, const v
 
 static EnumTable::Enums bodyTypeLookup[] =
                 {
-                { b2_staticBody,    "static"    },
-                { b2_kinematicBody, "kinematic" },
-                { b2_dynamicBody,   "dynamic"   },
+                { b2_staticBody,    "Static"    },
+                { b2_kinematicBody, "Kinematic" },
+                { b2_dynamicBody,   "Dynamic"   },
                 };
 
 EnumTable bodyTypeTable(sizeof(bodyTypeLookup) / sizeof(EnumTable::Enums), &bodyTypeLookup[0]);
@@ -3884,10 +3989,10 @@ EnumTable bodyTypeTable(sizeof(bodyTypeLookup) / sizeof(EnumTable::Enums), &body
 
 static EnumTable::Enums collisionShapeTypeLookup[] =
                 {
-                { b2Shape::e_circle,             "circle"   },
-                { b2Shape::e_edge,               "edge"     },
-                { b2Shape::e_polygon,            "polygon"  },
-                { b2Shape::e_chain,              "chain"    },
+                { b2Shape::e_circle,             "Circle"   },
+                { b2Shape::e_edge,               "Edge"     },
+                { b2Shape::e_polygon,            "Polygon"  },
+                { b2Shape::e_chain,              "Chain"    },
                 };
 
 EnumTable collisionShapeTypeTable(sizeof(collisionShapeTypeLookup) / sizeof(EnumTable::Enums), &collisionShapeTypeLookup[0]);

+ 2 - 2
engine/source/2d/sceneobject/SceneObject.h

@@ -241,8 +241,8 @@ protected:
     void                    initializeContactGathering( void );
 
     /// Taml callbacks.
-    virtual void            onTamlCustomWrite( TamlCustomProperties& customProperties );
-    virtual void            onTamlCustomRead( const TamlCustomProperties& customProperties );
+    virtual void            onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void            onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 public:
     SceneObject();

+ 26 - 23
engine/source/assets/assetQuery.cc

@@ -51,13 +51,13 @@ void AssetQuery::initPersistFields()
 
 //-----------------------------------------------------------------------------
 
-void AssetQuery::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void AssetQuery::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomWrite( customProperties );
+    Parent::onTamlCustomWrite( customNodes );
 
-    // Add property.
-    TamlCustomProperty* pProperty = customProperties.addProperty( ASSETQUERY_CUSTO_PROPERTY_NAME );
+    // Add node.
+    TamlCustomNode* pCustomNode = customNodes.addNode( ASSETQUERY_RESULTS_NODE_NAME );
 
     // Finish if no assets.
     if ( size() == 0 )
@@ -66,43 +66,46 @@ void AssetQuery::onTamlCustomWrite( TamlCustomProperties& customProperties )
     // Iterate asset.
     for( Vector<StringTableEntry>::iterator assetItr = begin(); assetItr != end(); ++assetItr )
     {
-        // Add alias.
-        TamlPropertyAlias* pAlias = pProperty->addAlias( ASSETQUERY_TYPE_NAME );
+        // Add asset node.
+        TamlCustomNode* pAssetNode = pCustomNode->addNode( ASSETQUERY_ASSETNODE_NAME );
 
-        // Add fields.
-        pAlias->addField( ASSETQUERY_ASSETID_FIELD_NAME, *assetItr );
+        // Add field.
+        pAssetNode->addField( ASSETQUERY_ASSETID_FIELD_NAME, *assetItr );
     }
 }
 
 //-----------------------------------------------------------------------------
 
-void AssetQuery::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void AssetQuery::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomRead( customProperties );
+    Parent::onTamlCustomRead( customNodes );
 
-    // Find custom property name.
-    const TamlCustomProperty* pProperty = customProperties.findProperty( ASSETQUERY_CUSTO_PROPERTY_NAME );
+    // Find custom node name.
+    const TamlCustomNode* pResultsNode = customNodes.findNode( ASSETQUERY_RESULTS_NODE_NAME );
 
-    // Finish if we don't have a property name.
-    if ( pProperty == NULL )
+    // Finish if we don't have a results name.
+    if ( pResultsNode == NULL )
         return;
 
-    // Fetch alias name.
-    StringTableEntry typeAliasName = StringTable->insert( ASSETQUERY_TYPE_NAME );
+    // Fetch node name.
+    StringTableEntry assetNodeName = StringTable->insert( ASSETQUERY_ASSETNODE_NAME );
 
-    // Iterate property alias.
-    for( TamlCustomProperty::const_iterator propertyAliasItr = pProperty->begin(); propertyAliasItr != pProperty->end(); ++propertyAliasItr )
+    // Fetch children asset nodes.
+    const TamlCustomNodeVector& assetNodes = pResultsNode->getChildren();
+
+    // Iterate asset nodes.
+    for( TamlCustomNodeVector::const_iterator assetNodeItr = assetNodes.begin(); assetNodeItr != assetNodes.end(); ++assetNodeItr )
     {
-        // Fetch property alias.
-        const TamlPropertyAlias* pAlias = *propertyAliasItr;
+        // Fetch asset node.
+        const TamlCustomNode* pAssetNode = *assetNodeItr;
 
-        // Skip if an unknown alias name.
-        if ( pAlias->mAliasName != typeAliasName )
+        // Skip if an unknown node name.
+        if ( pAssetNode->getNodeName() != assetNodeName )
             continue;
 
         // Fetch field.
-        const TamlPropertyField* pField = pAlias->findField( ASSETQUERY_ASSETID_FIELD_NAME );
+        const TamlCustomField* pField = pAssetNode->findField( ASSETQUERY_ASSETID_FIELD_NAME );
 
         // Do we find the field?
         if ( pField == NULL )

+ 4 - 4
engine/source/assets/assetQuery.h

@@ -37,8 +37,8 @@
 
 //-----------------------------------------------------------------------------
 
-#define ASSETQUERY_CUSTO_PROPERTY_NAME      "Results"
-#define ASSETQUERY_TYPE_NAME            "Asset"
+#define ASSETQUERY_RESULTS_NODE_NAME     "Results"
+#define ASSETQUERY_ASSETNODE_NAME        "Asset"
 #define ASSETQUERY_ASSETID_FIELD_NAME   "AssetId"
 
 //-----------------------------------------------------------------------------
@@ -49,8 +49,8 @@ private:
     typedef SimObject Parent;
 
 protected:
-    virtual void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    virtual void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
     static const char* getCount(void* obj, const char* data) { return Con::getIntArg(static_cast<AssetQuery*>(obj)->size()); }
     static bool writeCount( void* obj, StringTableEntry pFieldName ) { return false; }

+ 45 - 39
engine/source/assets/assetTagsManifest.cc

@@ -118,72 +118,75 @@ void AssetTagsManifest::renameAssetId( const char* pAssetIdFrom, const char* pAs
 
 //-----------------------------------------------------------------------------
 
-void AssetTagsManifest::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void AssetTagsManifest::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomWrite( customProperties );
+    Parent::onTamlCustomWrite( customNodes );
 
     // Finish if no tags.
     if ( mTagNameDatabase.size() == 0 )
         return;
 
-    // Add property.
-    TamlCustomProperty* pTagProperty = customProperties.addProperty( ASSETTAGS_TAGS_CUSTOMPROPERTY_NAME );
+    // Add node.
+    TamlCustomNode* pTagsNode = customNodes.addNode( ASSETTAGS_TAGS_NODE_NAME );
 
     // Iterate tags.
     for( typeTagNameHash::iterator tagItr = mTagNameDatabase.begin(); tagItr != mTagNameDatabase.end(); ++tagItr )
     {
-        // Add alias.
-        TamlPropertyAlias* pAlias = pTagProperty->addAlias( ASSETTAGS_TAGS_TYPE_NAME );
+        // Add tag node.
+        TamlCustomNode* pTagNode = pTagsNode->addNode( ASSETTAGS_TAGS_TYPE_NAME );
 
         // Add fields.
-        pAlias->addField( ASSETTAGS_TAGS_NAME_FIELD, tagItr->key );
+        pTagNode->addField( ASSETTAGS_TAGS_NAME_FIELD, tagItr->key );
     }
 
-    // Add property.
-    TamlCustomProperty* pAssetTagProperty = customProperties.addProperty( ASSETTAGS_ASSETS_CUSTOMPROPERTY_NAME );
+    // Add node.
+    TamlCustomNode* pAssetTagsNode = customNodes.addNode( ASSETTAGS_ASSETS_NODE_NAME );
 
     // Iterate asset locations.
     for( typeAssetToTagHash::iterator assetTagItr = mAssetToTagDatabase.begin(); assetTagItr != mAssetToTagDatabase.end(); ++assetTagItr )
     {
-        // Add alias.
-        TamlPropertyAlias* pAlias = pAssetTagProperty->addAlias( ASSETTAGS_ASSETS_TYPE_NAME );
+        // Add asset tag node.
+        TamlCustomNode* pAssetNode = pAssetTagsNode->addNode( ASSETTAGS_ASSETS_TYPE_NAME );
 
         // Add fields.
-        pAlias->addField( ASSETTAGS_ASSETS_ASSETID_FIELD, assetTagItr->key );
-        pAlias->addField( ASSETTAGS_ASSETS_TAG_FIELD, assetTagItr->value->mTagName );
+        pAssetNode->addField( ASSETTAGS_ASSETS_ASSETID_FIELD, assetTagItr->key );
+        pAssetNode->addField( ASSETTAGS_ASSETS_TAG_FIELD, assetTagItr->value->mTagName );
     }
 }
 
 //-----------------------------------------------------------------------------
 
-void AssetTagsManifest::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void AssetTagsManifest::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomRead( customProperties );
+    Parent::onTamlCustomRead( customNodes );
 
-    // Find custom property name.
-    const TamlCustomProperty* pTagProperty = customProperties.findProperty( ASSETTAGS_TAGS_CUSTOMPROPERTY_NAME );
+    // Find tags nodes.
+    const TamlCustomNode* pTagProperty = customNodes.findNode( ASSETTAGS_TAGS_NODE_NAME );
 
-    // Finish if we don't have a property name.
+    // Finish if we don't have a tags node name.
     if ( pTagProperty == NULL )
         return;
 
-    // Fetch alias name.
-    StringTableEntry tagAliasName = StringTable->insert( ASSETTAGS_TAGS_TYPE_NAME );
+    // Fetch node name.
+    StringTableEntry tagNodeName = StringTable->insert( ASSETTAGS_TAGS_TYPE_NAME );
 
-    // Iterate property alias.
-    for( TamlCustomProperty::const_iterator propertyAliasItr = pTagProperty->begin(); propertyAliasItr != pTagProperty->end(); ++propertyAliasItr )
+    // Fetch children asset nodes.
+    const TamlCustomNodeVector& tagNodes = pTagProperty->getChildren();
+
+    // Iterate tag nodes.
+    for( TamlCustomNodeVector::const_iterator tagNodeItr = tagNodes.begin(); tagNodeItr != tagNodes.end(); ++tagNodeItr )
     {
-        // Fetch property alias.
-        const TamlPropertyAlias* pAlias = *propertyAliasItr;
+        // Fetch tag node.
+        const TamlCustomNode* pTagNode = *tagNodeItr;
 
-        // Skip if an unknown alias name.
-        if ( pAlias->mAliasName != tagAliasName )
+        // Skip if an unknown node name.
+        if ( pTagNode->getNodeName() != tagNodeName )
             continue;
 
         // Fetch "Name" field.
-        const TamlPropertyField* pTagNameField = pAlias->findField( ASSETTAGS_TAGS_NAME_FIELD );
+        const TamlCustomField* pTagNameField = pTagNode->findField( ASSETTAGS_TAGS_NAME_FIELD );
 
         // Do we find the field?
         if ( pTagNameField == NULL )
@@ -197,28 +200,31 @@ void AssetTagsManifest::onTamlCustomRead( const TamlCustomProperties& customProp
         createTag( pTagNameField->getFieldValue() );
     }
 
-    // Find custom property name.
-    const TamlCustomProperty* pAssetTagProperty = customProperties.findProperty( ASSETTAGS_ASSETS_CUSTOMPROPERTY_NAME );
+    // Find asset tags node.
+    const TamlCustomNode* pAssetTagProperty = customNodes.findNode( ASSETTAGS_ASSETS_NODE_NAME );
 
-    // Finish if we don't have a property name.
+    // Finish if we don't have an asset tags node name.
     if ( pAssetTagProperty == NULL )
         return;
 
-    // Fetch alias name.
-    StringTableEntry assetTagAliasName = StringTable->insert( ASSETTAGS_ASSETS_TYPE_NAME );
+    // Fetch node name.
+    StringTableEntry assetTagNodeName = StringTable->insert( ASSETTAGS_ASSETS_TYPE_NAME );
+
+    // Fetch children asset tag nodes.
+    const TamlCustomNodeVector& assetTagNodes = pAssetTagProperty->getChildren();
 
     // Iterate property alias.
-    for( TamlCustomProperty::const_iterator propertyAliasItr = pAssetTagProperty->begin(); propertyAliasItr != pAssetTagProperty->end(); ++propertyAliasItr )
+    for( TamlCustomNodeVector::const_iterator assetTagNodeItr = assetTagNodes.begin(); assetTagNodeItr != assetTagNodes.end(); ++assetTagNodeItr )
     {
-        // Fetch property alias.
-        const TamlPropertyAlias* pAlias = *propertyAliasItr;
+        // Fetch asset node.
+        const TamlCustomNode* pAssetTagNode = *assetTagNodeItr;
 
-        // Skip if an unknown alias name.
-        if ( pAlias->mAliasName != assetTagAliasName )
+        // Skip if an unknown node name.
+        if ( pAssetTagNode->getNodeName() != assetTagNodeName )
             continue;
 
         // Fetch "AssetId" field.
-        const TamlPropertyField* pAssetIdField = pAlias->findField( ASSETTAGS_ASSETS_ASSETID_FIELD );
+        const TamlCustomField* pAssetIdField = pAssetTagNode->findField( ASSETTAGS_ASSETS_ASSETID_FIELD );
 
         // Do we find the field?
         if ( pAssetIdField == NULL )
@@ -229,7 +235,7 @@ void AssetTagsManifest::onTamlCustomRead( const TamlCustomProperties& customProp
         }
 
         // Fetch "Tag" field.
-        const TamlPropertyField* pTagField = pAlias->findField( ASSETTAGS_ASSETS_TAG_FIELD );
+        const TamlCustomField* pTagField = pAssetTagNode->findField( ASSETTAGS_ASSETS_TAG_FIELD );
 
         // Do we find the field?
         if ( pTagField == NULL )

+ 4 - 4
engine/source/assets/assetTagsManifest.h

@@ -41,11 +41,11 @@
 
 //-----------------------------------------------------------------------------
 
-#define ASSETTAGS_TAGS_CUSTOMPROPERTY_NAME      "Tags"
+#define ASSETTAGS_TAGS_NODE_NAME                "Tags"
 #define ASSETTAGS_TAGS_TYPE_NAME                "Tag"
 #define ASSETTAGS_TAGS_NAME_FIELD               "Name"
 
-#define ASSETTAGS_ASSETS_CUSTOMPROPERTY_NAME    "Assets"
+#define ASSETTAGS_ASSETS_NODE_NAME              "Assets"
 #define ASSETTAGS_ASSETS_TYPE_NAME              "Tag"
 #define ASSETTAGS_ASSETS_ASSETID_FIELD          "AssetId"
 #define ASSETTAGS_ASSETS_TAG_FIELD              "Name"
@@ -120,8 +120,8 @@ private:
     void renameAssetId( const char* pAssetIdFrom, const char* pAssetIdTo );
 
 protected:
-    virtual void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    virtual void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 public:
     AssetTagsManifest();

+ 61 - 49
engine/source/component/behaviors/behaviorComponent.cpp

@@ -886,10 +886,10 @@ const BehaviorComponent::typePortConnectionVector* BehaviorComponent::getBehavio
 
 //-----------------------------------------------------------------------------
 
-void BehaviorComponent::onTamlCustomWrite( TamlCustomProperties& customProperties )
+void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomWrite( customProperties );
+    Parent::onTamlCustomWrite( customNodes );
 
     // Fetch behavior count.
     const U32 behaviorCount = (U32)mBehaviors.size();
@@ -901,8 +901,8 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomProperties& customPropertie
     // Fetch behavior template asset field type.
     StringTableEntry behaviorTemplateAssetFieldType = StringTable->insert( BEHAVIORTEMPLATE_ASSET_FIELDTYPE );
 
-    // Add behavior property.
-    TamlCustomProperty* pBehaviorProperty = customProperties.addProperty( BEHAVIOR_CUSTOMPROPERTY_NAME );
+    // Add custom behaviors node.
+    TamlCustomNode* pCustomBehaviorNode = customNodes.addNode( BEHAVIOR_NODE_NAME );
 
     // Iterate behaviors.
     for( SimSet::iterator behaviorItr = mBehaviors.begin(); behaviorItr != mBehaviors.end(); ++behaviorItr )
@@ -913,11 +913,11 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomProperties& customPropertie
         // Fetch template.
         BehaviorTemplate* pBehaviorTemplate = pBehaviorInstance->getTemplate();
 
-        // Add behavior alias.
-        TamlPropertyAlias* pBehaviorAlias = pBehaviorProperty->addAlias( pBehaviorInstance->getTemplateName() );
+        // Add behavior node.
+        TamlCustomNode* pBehaviorNode = pCustomBehaviorNode->addNode( pBehaviorInstance->getTemplateName() );
 
         // Add behavior Id field.
-        pBehaviorAlias->addField( BEHAVIOR_ID_FIELD_NAME, pBehaviorInstance->getBehaviorId() );
+        pBehaviorNode->addField( BEHAVIOR_ID_FIELD_NAME, pBehaviorInstance->getBehaviorId() );
 
         // Fetch field count,
         const U32 behaviorFieldCount = pBehaviorTemplate->getBehaviorFieldCount();
@@ -942,7 +942,7 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomProperties& customPropertie
             const char* pFieldValue = pBehaviorInstance->getPrefixedDynamicDataField( pBehaviorField->mName, NULL, fieldType );
 
             // Add behavior field.
-            pBehaviorAlias->addField( pBehaviorField->mName, pFieldValue );
+            pBehaviorNode->addField( pBehaviorField->mName, pFieldValue );
         }
     }
 
@@ -953,8 +953,8 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomProperties& customPropertie
     if ( behaviorConnectionCount == 0 )
         return;
 
-    // Add behavior connection property.
-    TamlCustomProperty* pConnectionProperty = customProperties.addProperty( BEHAVIOR_CONNECTION_CUSTOMPROPERTY_NAME );
+    // Add custom behavior connection property.
+    TamlCustomNode* pCustomConnection = customNodes.addNode( BEHAVIOR_CONNECTION_NODE_NAME );
     
     // Iterate instance connections.
     for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
@@ -974,12 +974,12 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomProperties& customPropertie
                 // Fetch connection.
                 BehaviorPortConnection* pConnection = connectionItr;
 
-                // Add connection alias.
-                TamlPropertyAlias* pConnectionAlias = pConnectionProperty->addAlias( BEHAVIOR_CONNECTION_TYPE_NAME );
+                // Add connectionnode.
+                TamlCustomNode* pConnectionNode = pCustomConnection->addNode( BEHAVIOR_CONNECTION_TYPE_NAME );
 
                 // Add behavior field.
-                pConnectionAlias->addField( pConnection->mOutputName, pConnection->mOutputInstance->getBehaviorId() );
-                pConnectionAlias->addField( pConnection->mInputName, pConnection->mInputInstance->getBehaviorId() );
+                pConnectionNode->addField( pConnection->mOutputName, pConnection->mOutputInstance->getBehaviorId() );
+                pConnectionNode->addField( pConnection->mInputName, pConnection->mInputInstance->getBehaviorId() );
             }
         }
     }
@@ -987,16 +987,16 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomProperties& customPropertie
 
 //-----------------------------------------------------------------------------
 
-void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProperties )
+void BehaviorComponent::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Call parent.
-    Parent::onTamlCustomRead( customProperties );
+    Parent::onTamlCustomRead( customNodes );
 
-    // Find behavior custom property name.
-    const TamlCustomProperty* pCustomProperty = customProperties.findProperty( BEHAVIOR_CUSTOMPROPERTY_NAME );
+    // Find custom behaviors node.
+    const TamlCustomNode* pCustomBehaviorNode = customNodes.findNode( BEHAVIOR_NODE_NAME );
 
     // Do we have the property?
-    if ( pCustomProperty != NULL )
+    if ( pCustomBehaviorNode != NULL )
     {
         // Yes, so reset maximum behavior Id.
         S32 maximumBehaviorId = 0;
@@ -1007,23 +1007,26 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProp
         // Fetch behavior template asset field type.
         StringTableEntry behaviorTemplateAssetFieldType = StringTable->insert( BEHAVIORTEMPLATE_ASSET_FIELDTYPE );
 
-        // Iterate property alias.
-        for( TamlCustomProperty::const_iterator propertyAliasItr = pCustomProperty->begin(); propertyAliasItr != pCustomProperty->end(); ++propertyAliasItr )
+        // Fetch children behavior nodes.
+        const TamlCustomNodeVector& behaviorNodes = pCustomBehaviorNode->getChildren();
+
+        // Iterate behavior nodes.
+        for( TamlCustomNodeVector::const_iterator behaviorNodeItr = behaviorNodes.begin(); behaviorNodeItr != behaviorNodes.end(); ++behaviorNodeItr )
         {
-            // Fetch property alias.
-            TamlPropertyAlias* pPropertyAlias = *propertyAliasItr;
+            // Fetch behavior node.
+            TamlCustomNode* pBehaviorNode = *behaviorNodeItr;
 
             // Fetch template.
-            BehaviorTemplate* pTemplate = dynamic_cast<BehaviorTemplate *>( Sim::findObject( pPropertyAlias->mAliasName ) );
+            BehaviorTemplate* pTemplate = dynamic_cast<BehaviorTemplate *>( Sim::findObject( pBehaviorNode->getNodeName() ) );
 
             // Find template?
             if( pTemplate == NULL )
             {
                 // No, so warn appropriately.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Missing Behavior '%s'", pPropertyAlias->mAliasName );
+                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Missing Behavior '%s'", pBehaviorNode->getNodeName() );
 
                 if( isMethod( "onBehaviorMissing" ) )
-                    Con::executef( this, 2, "onBehaviorMissing", pPropertyAlias->mAliasName );
+                    Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
 
                 // Skip it.
                 continue;
@@ -1036,10 +1039,10 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProp
             if ( pBehaviorInstance == NULL )
             {
                 // No, so warn appropriately.
-                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Found behavior could not create an instance '%s'", pPropertyAlias->mAliasName );
+                Con::warnf( "BehaviorComponent::onTamlCustomRead() - Found behavior could not create an instance '%s'", pBehaviorNode->getNodeName() );
 
                 if( isMethod( "onBehaviorMissing" ) )
-                    Con::executef( this, 2, "onBehaviorMissing", pPropertyAlias->mAliasName );
+                    Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
 
                 // Skip it.
                 continue;
@@ -1047,17 +1050,20 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProp
 
             S32 behaviorId = 0;
 
-            // Iterate property fields.
-            for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
+            // Fetch field nodes.
+            const TamlCustomFieldVector& fields = pBehaviorNode->getFields();
+
+            // Iterate fields.
+            for ( TamlCustomFieldVector::const_iterator nodeFieldItr = fields.begin(); nodeFieldItr != fields.end(); ++nodeFieldItr )
             {
-                // Fetch property field.
-                TamlPropertyField* pPropertyField = *propertyFieldItr;
+                // Fetch field.
+                TamlCustomField* pField = *nodeFieldItr;
 
                 // Fetch field name.
-                const char* pFieldName = pPropertyField->getFieldName();
+                const char* pFieldName = pField->getFieldName();
 
                 // Fetch field value.
-                const char* pFieldValue = pPropertyField->getFieldValue();
+                const char* pFieldValue = pField->getFieldValue();
 
                 // Is this the behavior field Id name?
                 if ( pFieldName == behaviorFieldIdName )
@@ -1071,7 +1077,7 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProp
                         // No, so warn.
                         Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered an invalid behavior Id of '%d' on behavior '%s'.",
                             behaviorId,
-                            pPropertyAlias->mAliasName );
+                            pBehaviorNode->getNodeName() );
                     }
 
                     // Update maximum behavior Id found.
@@ -1096,7 +1102,7 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProp
                 }
 
                 // Set field.
-                pBehaviorInstance->setPrefixedDynamicDataField( pPropertyField->getFieldName(), NULL, pPropertyField->getFieldValue(), fieldType );
+                pBehaviorInstance->setPrefixedDynamicDataField( pField->getFieldName(), NULL, pField->getFieldValue(), fieldType );
             }
 
             // Add behavior.
@@ -1111,27 +1117,33 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProp
         mMasterBehaviorId = (U32)maximumBehaviorId+1;
     }
 
-    // Find behavior connections custom property name.
-    const TamlCustomProperty* pConnectionProperty = customProperties.findProperty( BEHAVIOR_CONNECTION_CUSTOMPROPERTY_NAME );
+    // Find behavior connections custom node.
+    const TamlCustomNode* pCustomConnectionNode = customNodes.findNode( BEHAVIOR_CONNECTION_NODE_NAME );
 
-    // Do we have the property?
-    if ( pConnectionProperty != NULL )
+    // Do we have the custom connection node?
+    if ( pCustomConnectionNode != NULL )
     {
-        // Yes, so insert connection alias.
-        StringTableEntry connectionAlias = StringTable->insert( BEHAVIOR_CONNECTION_TYPE_NAME );
+        // Yes, so fetch the connection node name..
+        StringTableEntry connectionNodeName = StringTable->insert( BEHAVIOR_CONNECTION_TYPE_NAME );
+
+        // Fetch children connection nodes.
+        const TamlCustomNodeVector& connectionNodes = pCustomConnectionNode->getChildren();
 
         // Iterate property alias.
-        for( TamlCustomProperty::const_iterator propertyAliasItr = pConnectionProperty->begin(); propertyAliasItr != pConnectionProperty->end(); ++propertyAliasItr )
+        for( TamlCustomNodeVector::const_iterator connectionNodeItr = connectionNodes.begin(); connectionNodeItr != connectionNodes.end(); ++connectionNodeItr )
         {
-            // Fetch property alias.
-            TamlPropertyAlias* pPropertyAlias = *propertyAliasItr;
+            // Fetch connection node.
+            TamlCustomNode* pConnectionNode = *connectionNodeItr;
 
             // Skip if the alias isn't a connection.
-            if ( pPropertyAlias->mAliasName != connectionAlias )
+            if ( pConnectionNode->getNodeName() != connectionNodeName )
                 continue;
 
+            // Fetch field nodes.
+            const TamlCustomFieldVector& connectionFieldNodes = pConnectionNode->getFields();
+
             // Are there two properties?
-            if ( pPropertyAlias->size() != 2 )
+            if ( connectionFieldNodes.size() != 2 )
             {
                 // No, so warn.
                 Con::warnf( "BehaviorComponent::onTamlCustomRead() - Encountered a behavior connection with more than two connection fields." );
@@ -1139,8 +1151,8 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomProperties& customProp
             }
 
             // Fetch property field #1.
-            TamlPropertyField* pPropertyField1 = *pPropertyAlias->begin();
-            TamlPropertyField* pPropertyField2 = *(pPropertyAlias->begin()+1);
+            TamlCustomField* pPropertyField1 = *connectionFieldNodes.begin();
+            TamlCustomField* pPropertyField2 = *(connectionFieldNodes.begin()+1);
            
             // Fetch behavior instances #1.
             BehaviorInstance* pBehaviorInstance1 = getBehaviorByInstanceId( dAtoi( pPropertyField1->getFieldValue() ) );

+ 4 - 4
engine/source/component/behaviors/behaviorComponent.h

@@ -34,8 +34,8 @@
 //-----------------------------------------------------------------------------
 
 #define BEHAVIOR_ID_FIELD_NAME                  "Id"
-#define BEHAVIOR_CUSTOMPROPERTY_NAME                "Behaviors"
-#define BEHAVIOR_CONNECTION_CUSTOMPROPERTY_NAME     "BehaviorConnections"
+#define BEHAVIOR_NODE_NAME                      "Behaviors"
+#define BEHAVIOR_CONNECTION_NODE_NAME           "BehaviorConnections"
 #define BEHAVIOR_CONNECTION_TYPE_NAME           "Connection"
 
 //-----------------------------------------------------------------------------
@@ -88,8 +88,8 @@ protected:
     virtual const char* _callMethod( U32 argc, const char *argv[], bool callThis = true );
 
     /// Taml callbacks.
-    virtual void onTamlCustomWrite( TamlCustomProperties& customProperties );
-    virtual void onTamlCustomRead( const TamlCustomProperties& customProperties );
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 private:
     void destroyBehaviorOutputConnections( BehaviorInstance* pOutputBehavior );

+ 0 - 2
engine/source/memory/frameAllocator.h

@@ -281,12 +281,10 @@ public:
 
    // This ifdef is to satisfy the ever so pedantic GCC compiler
    //  Which seems to upset visual studio.
-#if defined(TORQUE_COMPILER_GCC)   
    T& operator[]( const U32 idx ) { return mMemory[idx]; }
    const T& operator[]( const U32 idx ) const { return mMemory[idx]; }
    T& operator[]( const S32 idx ) { return mMemory[idx]; }
    const T& operator[]( const S32 idx ) const { return mMemory[idx]; }   
-#endif
 };
 
 //-----------------------------------------------------------------------------

+ 59 - 62
engine/source/persistence/taml/taml.cc

@@ -379,7 +379,7 @@ Taml::TamlFormatMode Taml::getFileAutoFormatMode( const char* pFilename )
 
 //-----------------------------------------------------------------------------
 
-TamlWriteNode* Taml::compileObject( SimObject* pSimObject )
+TamlWriteNode* Taml::compileObject( SimObject* pSimObject, const bool forceId )
 {
     // Debug Profiling.
     PROFILE_SCOPE(Taml_CompileObject);
@@ -426,6 +426,13 @@ TamlWriteNode* Taml::compileObject( SimObject* pSimObject )
     TamlWriteNode* pNewNode = new TamlWriteNode();
     pNewNode->set( pSimObject );
 
+    // Is an Id being forced for this object?
+    if ( forceId )
+    {
+        // Yes, so allocate one.
+        pNewNode->mRefId = ++mMasterNodeId;
+    }
+
     // Push new node.
     mCompiledNodes.push_back( pNewNode );
 
@@ -446,8 +453,8 @@ TamlWriteNode* Taml::compileObject( SimObject* pSimObject )
     // Compile children.
     compileChildren( pNewNode );
 
-    // Compile custom properties.
-    compileCustomProperties( pNewNode );
+    // Compile custom state.
+    compileCustomState( pNewNode );
 
     // Are there any Taml callbacks?
     if ( pNewNode->mpTamlCallbacks != NULL )
@@ -661,93 +668,83 @@ void Taml::compileChildren( TamlWriteNode* pTamlWriteNode )
 
 //-----------------------------------------------------------------------------
 
-void Taml::compileCustomProperties( TamlWriteNode* pTamlWriteNode )
+void Taml::compileCustomState( TamlWriteNode* pTamlWriteNode )
 {
     // Debug Profiling.
     PROFILE_SCOPE(Taml_CompileCustomProperties);
 
     // Sanity!
-    AssertFatal( pTamlWriteNode != NULL, "Cannot compile custom properties on a NULL node." );
-    AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile custom properties on a node with no object." );
+    AssertFatal( pTamlWriteNode != NULL, "Cannot compile custom state on a NULL node." );
+    AssertFatal( pTamlWriteNode->mpSimObject != NULL, "Cannot compile custom state on a node with no object." );
 
-    // Fetch the custom properties on the write node.
-    TamlCustomProperties& customProperties = pTamlWriteNode->mCustomProperties;
+    // Fetch the custom node on the write node.
+    TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes;
 
     // Are there any Taml callbacks?
     if ( pTamlWriteNode->mpTamlCallbacks != NULL )
     {
         // Yes, so call it.
-        tamlCustomWrite( pTamlWriteNode->mpTamlCallbacks, customProperties );
+        tamlCustomWrite( pTamlWriteNode->mpTamlCallbacks, customNodes );
     }
 
-    // Finish if no custom properties to process.
-    if ( customProperties.size() == 0 )
-        return;
+    // Fetch custom nodes.
+    const TamlCustomNodeVector& nodes = customNodes.getNodes();
 
+    // Finish if no custom nodes to process.
+    if ( nodes.size() == 0 )
+        return;
+    
     // Iterate custom properties.
-    for( TamlCustomPropertyVector::iterator propertyItr = customProperties.begin(); propertyItr != customProperties.end(); ++propertyItr )
+    for( TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr )
     {
-        TamlCustomProperty* pCustomProperty = *propertyItr;
-
-        // Iterate alias.
-        for( TamlPropertyAliasVector::iterator typeAliasItr = pCustomProperty->begin(); typeAliasItr != pCustomProperty->end(); ++typeAliasItr )
-        {
-            TamlPropertyAlias* pAlias = *typeAliasItr;
+        // Fetch the custom node.
+        TamlCustomNode* pCustomNode = *customNodesItr;
 
-            // Iterate the fields.
-            for( TamlPropertyFieldVector::iterator fieldItr = pAlias->begin(); fieldItr != pAlias->end(); ++fieldItr )
-            {
-                TamlPropertyField* pPropertyField = *fieldItr;
+        // Compile custom node state.
+        compileCustomNodeState( pCustomNode );
+    }
+}
 
-                // Skip if not an object field.
-                if ( !pPropertyField->isObjectField() )
-                    continue;
+//-----------------------------------------------------------------------------
 
-                // Compile the object.
-                TamlWriteNode* pCompiledWriteNode = compileObject( pPropertyField->getFieldObject() );
+void Taml::compileCustomNodeState( TamlCustomNode* pCustomNode )
+{
+    // Sanity!
+    AssertFatal( pCustomNode != NULL, "Taml: Cannot compile NULL custom node state." );
 
-                // Set reference field.
-                pCompiledWriteNode->mRefField = pPropertyField->getFieldName();
+    // Fetch children.
+    const TamlCustomNodeVector& children = pCustomNode->getChildren();
 
-                // Set the write node for the property field.
-                pPropertyField->setWriteNode( pCompiledWriteNode );
-            }
-        }
-    }
+    // Fetch proxy object.
+    SimObject* pProxyObject = pCustomNode->getProxyObject<SimObject>(false);
 
-#if 0
-    // Iterate the custom properties removing ignored items.
-    for( S32 customPropertyIndex = 0; customPropertyIndex < customProperties.size(); ++customPropertyIndex )
+    // Do we have a proxy object?
+    if ( pProxyObject != NULL )
     {
-        // Fetch the custom property.
-        TamlCustomProperty* pCustomProperty = customProperties.at( customPropertyIndex );
-
-        // Skip if we are not ignoring the custom property if empty.
-        if ( !pCustomProperty->mIgnoreEmpty )
-            continue;
-
-        // Iterate the alias.
-        for ( S32 typeAliasIndex = 0; typeAliasIndex < pCustomProperty->size(); ++typeAliasIndex )
-        {
-            // Fetch the alias.
-            TamlPropertyAlias* pAlias = pCustomProperty->at( typeAliasIndex );
+        // Yes, so sanity!
+        AssertFatal( children.size() == 0, "Taml: Cannot compile a proxy object on a custom node that has children." );
 
-            // Skip If we're not ignoring the alias or the custom property is not empty.
-            if ( !pAlias->mIgnoreEmpty && pAlias->size() != 0 )
-                continue;
+        // Yes, so compile it.
+        // NOTE: We force an Id for custom compiled objects so we guarantee an Id.  The reason for this is fairly
+        // weak in that the XML parser currently has no way of distinguishing between a compiled object node
+        // and a custom node.  If the node has an Id or an Id-Ref then it's obviously an object and should be parsed as such.
+        pCustomNode->setWriteNode( compileObject( pProxyObject, true ) );
+        return;
+    }
 
-            // Remove the alias.
-            pCustomProperty->removeAlias( typeAliasIndex-- );
-        }
+    // Finish if no children.
+    if ( children.size() == 0 )
+        return;
 
-        // Skip if the custom property is not empty.
-        if ( pCustomProperty->size() != 0 )
-            continue;
+    // Iterate children.
+    for( TamlCustomNodeVector::const_iterator childItr = children.begin(); childItr != children.end(); ++childItr )
+    {
+        // Fetch shape node.
+        TamlCustomNode* pChildNode = *childItr;
 
-        // Remove the custom property.
-        customProperties.removeProperty( customPropertyIndex-- );
+        // Compile the child.
+        compileCustomNodeState( pChildNode );
     }
-#endif
 }
 
 //-----------------------------------------------------------------------------

+ 6 - 5
engine/source/persistence/taml/taml.h

@@ -103,11 +103,12 @@ private:
 private:
     void resetCompilation( void );
 
-    TamlWriteNode* compileObject( SimObject* pSimObject );
+    TamlWriteNode* compileObject( SimObject* pSimObject, const bool forceId = false );
     void compileStaticFields( TamlWriteNode* pTamlWriteNode );
     void compileDynamicFields( TamlWriteNode* pTamlWriteNode );
     void compileChildren( TamlWriteNode* pTamlWriteNode );
-    void compileCustomProperties( TamlWriteNode* pTamlWriteNode );
+    void compileCustomState( TamlWriteNode* pTamlWriteNode );
+    void compileCustomNodeState( TamlCustomNode* pCustomNode );
 
     bool write( FileStream& stream, SimObject* pSimObject, const TamlFormatMode formatMode );
     SimObject* read( FileStream& stream, const TamlFormatMode formatMode );
@@ -129,10 +130,10 @@ private:
     inline void tamlPreWrite( TamlCallbacks* pCallbacks )                                           { pCallbacks->onTamlPreWrite(); }
     inline void tamlPostWrite( TamlCallbacks* pCallbacks )                                          { pCallbacks->onTamlPostWrite(); }
     inline void tamlPreRead( TamlCallbacks* pCallbacks )                                            { pCallbacks->onTamlPreRead(); }
-    inline void tamlPostRead( TamlCallbacks* pCallbacks, const TamlCustomProperties& customProperties )   { pCallbacks->onTamlPostRead( customProperties ); }
+    inline void tamlPostRead( TamlCallbacks* pCallbacks, const TamlCustomNodes& customNodes )       { pCallbacks->onTamlPostRead( customNodes ); }
     inline void tamlAddParent( TamlCallbacks* pCallbacks, SimObject* pParentObject )                { pCallbacks->onTamlAddParent( pParentObject ); }
-    inline void tamlCustomWrite( TamlCallbacks* pCallbacks, TamlCustomProperties& customProperties )      { pCallbacks->onTamlCustomWrite( customProperties ); }
-    inline void tamlCustomRead( TamlCallbacks* pCallbacks, const TamlCustomProperties& customProperties ) { pCallbacks->onTamlCustomRead( customProperties ); }
+    inline void tamlCustomWrite( TamlCallbacks* pCallbacks, TamlCustomNodes& customNodes )          { pCallbacks->onTamlCustomWrite( customNodes ); }
+    inline void tamlCustomRead( TamlCallbacks* pCallbacks, const TamlCustomNodes& customNodes )     { pCallbacks->onTamlCustomRead( customNodes ); }
 
 public:
     Taml();

+ 110 - 97
engine/source/persistence/taml/tamlBinaryReader.cc

@@ -191,7 +191,7 @@ SimObject* TamlBinaryReader::parseElement( Stream& stream, const U32 versionId )
     }
 
     // Parse custom elements.
-    TamlCustomProperties customProperties;
+    TamlCustomNodes customProperties;
 
     // Parse children.
     parseChildren( stream, pCallbacks, pSimObject, versionId );
@@ -212,102 +212,6 @@ SimObject* TamlBinaryReader::parseElement( Stream& stream, const U32 versionId )
 
 //-----------------------------------------------------------------------------
 
-void TamlBinaryReader::parseCustomElements( Stream& stream, TamlCallbacks* pCallbacks, TamlCustomProperties& customProperties, const U32 versionId )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(TamlBinaryReader_ParseCustomElement);
-
-    // Read custom element count.
-    U32 customPropertyCount;
-    stream.read( &customPropertyCount );
-
-    // Finish if no custom properties.
-    if ( customPropertyCount == 0 )
-        return;
-
-    // Iterate custom properties.
-    for ( U32 propertyIndex = 0; propertyIndex < customPropertyCount; ++propertyIndex )
-    {
-        // Read custom element name.
-        StringTableEntry propertyName = stream.readSTString();
-
-        // Add custom property.
-        TamlCustomProperty* pCustomProperty = customProperties.addProperty( propertyName );
-
-        // Read property alias count.
-        U32 propertyAliasCount;
-        stream.read( &propertyAliasCount );
-
-        // Skip if no property alias.
-        if ( propertyAliasCount == 0 )
-            continue;
-
-        // Iterate property alias.
-        for( U32 propertyAliasIndex = 0; propertyAliasIndex < propertyAliasCount; ++propertyAliasIndex )
-        {
-            // Read property alias name.
-            StringTableEntry propertyAliasName = stream.readSTString();
-
-            // Add property alias.
-            TamlPropertyAlias* pPropertyAlias = pCustomProperty->addAlias( propertyAliasName );
-
-            // Read property field count.
-            U32 propertyFieldCount;
-            stream.read( &propertyFieldCount );
-
-            // Skip if no property fields.
-            if ( propertyFieldCount == 0 )
-                continue;
-
-            // Iterate property fields.
-            for( U32 propertyFieldIndex = 0; propertyFieldIndex < propertyFieldCount; ++propertyFieldIndex )
-            {
-                // Read is object field flag.
-                bool isObjectField;
-                stream.read( &isObjectField );
-
-                // Is it an object field?
-                if ( isObjectField )
-                {
-                    // Yes, so read reference field.
-                    StringTableEntry fieldName = stream.readSTString();
-
-                    // Read field object.
-                    SimObject* pFieldObject = parseElement( stream, versionId );
-
-                    // Add property field.
-                    pPropertyAlias->addField( fieldName, pFieldObject );
-                }
-                else
-                {
-                    // No, so read field name.
-                    StringTableEntry propertyFieldName = stream.readSTString();
-
-                    // Read field value.
-                    char valueBuffer[MAX_TAML_PROPERTY_FIELDVALUE_LENGTH];
-                    stream.readLongString( MAX_TAML_PROPERTY_FIELDVALUE_LENGTH, valueBuffer );
-
-                    // Add property field.
-                    pPropertyAlias->addField( propertyFieldName, valueBuffer );
-                }
-            }
-        }
-    }
-
-    // Do we have callbacks?
-    if ( pCallbacks == NULL )
-    {
-        // No, so warn.
-        Con::warnf( "Taml: Encountered custom data but object does not support custom data." );
-        return;
-    }
-
-    // Custom read callback.
-    mpTaml->tamlCustomRead( pCallbacks, customProperties );
-}
-
-//-----------------------------------------------------------------------------
-
 void TamlBinaryReader::parseAttributes( Stream& stream, SimObject* pSimObject, const U32 versionId )
 {
     // Debug Profiling.
@@ -391,3 +295,112 @@ void TamlBinaryReader::parseChildren( Stream& stream, TamlCallbacks* pCallbacks,
         }
     }
 }
+
+//-----------------------------------------------------------------------------
+
+void TamlBinaryReader::parseCustomElements( Stream& stream, TamlCallbacks* pCallbacks, TamlCustomNodes& customNodes, const U32 versionId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(TamlBinaryReader_ParseCustomElement);
+
+    // Read custom node count.
+    U32 customNodeCount;
+    stream.read( &customNodeCount );
+
+    // Finish if no custom nodes.
+    if ( customNodeCount == 0 )
+        return;
+
+    // Iterate custom nodes.
+    for ( U32 nodeIndex = 0; nodeIndex < customNodeCount; ++nodeIndex )
+    {
+        //Read custom node name.
+        StringTableEntry nodeName = stream.readSTString();
+
+        // Add custom node.
+        TamlCustomNode* pCustomNode = customNodes.addNode( nodeName );
+
+        // Parse the custom node.
+        parseCustomNode( stream, pCustomNode, versionId );
+    }
+
+    // Do we have callbacks?
+    if ( pCallbacks == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Taml: Encountered custom data but object does not support custom data." );
+        return;
+    }
+
+    // Custom read callback.
+    mpTaml->tamlCustomRead( pCallbacks, customNodes );
+}
+
+//-----------------------------------------------------------------------------
+
+void TamlBinaryReader::parseCustomNode( Stream& stream, TamlCustomNode* pCustomNode, const U32 versionId )
+{
+    // Fetch if a proxy object.
+    bool isProxyObject;
+    stream.read( &isProxyObject );
+
+    // Is this a proxy object?
+    if ( isProxyObject )
+    {
+        // Yes, so parse proxy object.
+        SimObject* pProxyObject = parseElement( stream, versionId );
+
+        // Add child node.
+        pCustomNode->addNode( pProxyObject );
+
+        return;
+    }
+
+    // No, so read custom node name.
+    StringTableEntry nodeName = stream.readSTString();
+
+    // Add child node.
+    TamlCustomNode* pChildNode = pCustomNode->addNode( nodeName );
+
+    // Read child node text.
+    char childNodeTextBuffer[MAX_TAML_NODE_FIELDVALUE_LENGTH];
+    stream.readLongString( MAX_TAML_NODE_FIELDVALUE_LENGTH, childNodeTextBuffer );
+    pChildNode->setNodeText( childNodeTextBuffer );
+
+    // Read child node count.
+    U32 childNodeCount;
+    stream.read( &childNodeCount );
+
+    // Do we have any children nodes?
+    if ( childNodeCount > 0 )
+    {
+        // Yes, so parse children nodes.
+        for( U32 childIndex = 0; childIndex < childNodeCount; ++childIndex )
+        {
+            // Parse child node.
+            parseCustomNode( stream, pChildNode, versionId );
+        }
+    }
+
+    // Read child field count.
+    U32 childFieldCount;
+    stream.read( &childFieldCount );
+
+    // Do we have any child fields?
+    if ( childFieldCount > 0 )
+    {
+        // Yes, so parse child fields.
+        for( U32 childFieldIndex = 0; childFieldIndex < childFieldCount; ++childFieldIndex )
+        {
+            // Read field name.
+            StringTableEntry fieldName = stream.readSTString();
+
+            // Read field value.
+            char valueBuffer[MAX_TAML_NODE_FIELDVALUE_LENGTH];
+            stream.readLongString( MAX_TAML_NODE_FIELDVALUE_LENGTH, valueBuffer );
+
+            // Add field.
+            pChildNode->addField( fieldName, valueBuffer );
+        }
+    }
+}

+ 2 - 1
engine/source/persistence/taml/tamlBinaryReader.h

@@ -58,9 +58,10 @@ private:
     void resetParse( void );
 
     SimObject* parseElement( Stream& stream, const U32 versionId );
-    void parseCustomElements( Stream& stream, TamlCallbacks* pCallbacks, TamlCustomProperties& customProperties, const U32 versionId );
     void parseAttributes( Stream& stream, SimObject* pSimObject, const U32 versionId );
     void parseChildren( Stream& stream, TamlCallbacks* pCallbacks, SimObject* pSimObject, const U32 versionId );
+    void parseCustomElements( Stream& stream, TamlCallbacks* pCallbacks, TamlCustomNodes& customNodes, const U32 versionId );
+    void parseCustomNode( Stream& stream, TamlCustomNode* pCustomNode, const U32 versionId );
 };
 
 #endif // _TAML_BINARYREADER_H_

+ 116 - 83
engine/source/persistence/taml/tamlBinaryWriter.cc

@@ -126,89 +126,6 @@ void TamlBinaryWriter::writeElement( Stream& stream, const TamlWriteNode* pTamlW
 
 //-----------------------------------------------------------------------------
 
-void TamlBinaryWriter::writeCustomElements( Stream& stream, const TamlWriteNode* pTamlWriteNode )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(TamlBinaryWriter_WriteCustomElements);
-
-    // Fetch custom properties.
-    const TamlCustomProperties& customProperties = pTamlWriteNode->mCustomProperties;
-
-    // Write custom element count.
-    stream.write( (U32)customProperties.size() );
-
-    // Iterate custom properties.
-    for( TamlCustomProperties::const_iterator customPropertyItr = customProperties.begin(); customPropertyItr != customProperties.end(); ++customPropertyItr )
-    {
-        // Fetch custom property.
-        TamlCustomProperty* pCustomProperty = *customPropertyItr;
-
-        // Write custom element name.
-        stream.writeString( pCustomProperty->mPropertyName );
-
-        // Fetch property alias count.
-        U32 propertyAliasCount = (U32)pCustomProperty->size();
-
-        // Write property count.
-        stream.write( propertyAliasCount );
-
-        // Skip if no property alias.
-        if (propertyAliasCount == 0 )
-            continue;
-
-        // Iterate property alias.
-        for( TamlCustomProperty::const_iterator propertyAliasItr = pCustomProperty->begin(); propertyAliasItr != pCustomProperty->end(); ++propertyAliasItr )
-        {
-            // Fetch property alias.
-            TamlPropertyAlias* pPropertyAlias = *propertyAliasItr;
-
-            // Write property alias name.
-            stream.writeString( pPropertyAlias->mAliasName );
-
-            // Write property field count.
-            stream.write( (U32)pPropertyAlias->size() );
-
-            // Skip if no property fields.
-            if ( pPropertyAlias->size() == 0 )
-                continue;
-
-            // Iterate property fields.
-            for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
-            {
-                // Fetch property field.
-                TamlPropertyField* pPropertyField = *propertyFieldItr;
-
-                // Fetch object field flag,
-                const bool isObjectField = pPropertyField->isObjectField();
-
-                // Write flag.
-                stream.write( isObjectField );
-
-                // Is it an object field?
-                if ( isObjectField )
-                {
-                    // Yes, so fetch write node.
-                    const TamlWriteNode* pObjectWriteField = pPropertyField->getWriteNode();
-
-                    // Write reference field.
-                    stream.writeString( pObjectWriteField->mRefField );
-
-                    // Write field object.
-                    writeElement( stream, pObjectWriteField );
-                }
-                else
-                {
-                    // No, so write property attribute.
-                    stream.writeString( pPropertyField->getFieldName() );
-                    stream.writeLongString( MAX_TAML_PROPERTY_FIELDVALUE_LENGTH, pPropertyField->getFieldValue() );
-                }
-            }
-        }
-    }
-}
-
-//-----------------------------------------------------------------------------
-
 void TamlBinaryWriter::writeAttributes( Stream& stream, const TamlWriteNode* pTamlWriteNode )
 {
     // Debug Profiling.
@@ -261,4 +178,120 @@ void TamlBinaryWriter::writeChildren( Stream& stream, const TamlWriteNode* pTaml
         // Write child.
         writeElement( stream, (*itr) );
     }
+}
+
+//-----------------------------------------------------------------------------
+
+void TamlBinaryWriter::writeCustomElements( Stream& stream, const TamlWriteNode* pTamlWriteNode )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(TamlBinaryWriter_WriteCustomElements);
+
+    // Fetch custom nodes.
+    const TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes;
+
+    // Fetch custom nodes.
+    const TamlCustomNodeVector& nodes = customNodes.getNodes();
+
+    // Write custom node count.
+    stream.write( (U32)nodes.size() );
+
+    // Finish if there are no nodes.
+    if ( nodes.size() == 0 )
+        return;
+
+    // Iterate custom nodes.
+    for( TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr )
+    {
+        // Fetch the custom node.
+        TamlCustomNode* pCustomNode = *customNodesItr;
+
+        // Write custom node name.
+        stream.writeString( pCustomNode->getNodeName() );
+
+        // Fetch node children.
+        const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren();
+
+        // Iterate children nodes.
+        for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr )
+        {
+            // Fetch child node.
+            const TamlCustomNode* pChildNode = *childNodeItr;
+
+            // Write the custom node.
+            writeCustomNode( stream, pChildNode );
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void TamlBinaryWriter::writeCustomNode( Stream& stream, const TamlCustomNode* pCustomNode )
+{
+    // Is the node a proxy object?
+    if ( pCustomNode->isProxyObject() )
+    {
+        // Yes, so flag as proxy object.
+        stream.write( true );
+
+        // Write the element.
+        writeElement( stream, pCustomNode->getProxyWriteNode() );
+        return;
+    }
+
+    // No, so flag as custom node.
+    stream.write( false );
+
+    // Write custom node name.
+    stream.writeString( pCustomNode->getNodeName() );
+
+    // Write custom node text.
+    stream.writeString( pCustomNode->getNodeTextField().getFieldValue(), MAX_TAML_NODE_FIELDVALUE_LENGTH );
+
+    // Fetch node children.
+    const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren();
+
+    // Fetch child node count.
+    const U32 childNodeCount = (U32)nodeChildren.size();
+
+    // Write custom node count.
+    stream.write( childNodeCount );
+
+    // Do we have any children nodes.
+    if ( childNodeCount > 0 )
+    {
+        // Yes, so iterate children nodes.
+        for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr )
+        {
+            // Fetch child node.
+            const TamlCustomNode* pChildNode = *childNodeItr;
+
+            // Write the custom node.
+            writeCustomNode( stream, pChildNode );
+        }
+    }
+
+    // Fetch fields.
+    const TamlCustomFieldVector& fields = pCustomNode->getFields();
+
+    // Fetch child field count.
+    const U32 childFieldCount = (U32)fields.size();
+
+    // Write custom field count.
+    stream.write( childFieldCount );
+
+    // Do we have any child fields?
+    if ( childFieldCount > 0 )
+    {
+        // Yes, so iterate  fields.
+        for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
+        {
+            // Fetch node field.
+            const TamlCustomField* pField = *fieldItr;
+
+            // Write the node field.
+            stream.writeString( pField->getFieldName() );
+            stream.writeLongString( MAX_TAML_NODE_FIELDVALUE_LENGTH, pField->getFieldValue() );
+        }
+    }
 }

+ 3 - 2
engine/source/persistence/taml/tamlBinaryWriter.h

@@ -34,7 +34,7 @@ class TamlBinaryWriter
 public:
     TamlBinaryWriter( Taml* pTaml ) :
         mpTaml( pTaml ),
-        mVersionId(1)
+        mVersionId(2)
     {
     }
     virtual ~TamlBinaryWriter() {}
@@ -48,9 +48,10 @@ private:
 
 private:
     void writeElement( Stream& stream, const TamlWriteNode* pTamlWriteNode );
-    void writeCustomElements( Stream& stream, const TamlWriteNode* pTamlWriteNode );
     void writeAttributes( Stream& stream, const TamlWriteNode* pTamlWriteNode );
     void writeChildren( Stream& stream, const TamlWriteNode* pTamlWriteNode );
+    void writeCustomElements( Stream& stream, const TamlWriteNode* pTamlWriteNode );
+    void writeCustomNode( Stream& stream, const TamlCustomNode* pCustomNode );
 };
 
 #endif // _TAML_BINARYWRITER_H_

+ 4 - 4
engine/source/persistence/taml/tamlCallbacks.h

@@ -25,7 +25,7 @@
 
 //-----------------------------------------------------------------------------
 
-class TamlCustomProperties;
+class TamlCustomNodes;
 class SimObject;
 
 //-----------------------------------------------------------------------------
@@ -46,16 +46,16 @@ private:
 
     /// Called after Taml has finished reading the object.
     /// The custom properties is additionally passed here for object who want to process it at the end of reading.
-    virtual void onTamlPostRead( const TamlCustomProperties& customProperties ) = 0;
+    virtual void onTamlPostRead( const TamlCustomNodes& customNodes ) = 0;
 
     /// Called after Taml has finished reading the object and has added the object to any parent.
     virtual void onTamlAddParent( SimObject* pParentObject ) = 0;
 
     /// Called during the writing of the object to allow custom properties to be written.
-    virtual void onTamlCustomWrite( TamlCustomProperties& customProperties ) = 0;
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes ) = 0;
 
     /// Called during the reading of the object to allow custom properties to be read.
-    virtual void onTamlCustomRead( const TamlCustomProperties& customProperties ) = 0;
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes ) = 0;
 };
 
 #endif // _TAML_CALLBACKS_H_

+ 9 - 56
engine/source/persistence/taml/tamlCustom.cc

@@ -28,19 +28,12 @@
 
 //-----------------------------------------------------------------------------
 
-void TamlPropertyField::resetState( void )
-{
-    mFieldName = StringTable->EmptyString;
-    *mFieldValue = 0;
-
-    // We don't need to delete the write node as it'll get destroyed when the compilation is reset!
-    mpFieldWriteNode = NULL;
-    mpFieldObject = NULL;
-}
+FactoryCache<TamlCustomField> TamlCustomFieldFactory;
+FactoryCache<TamlCustomNode> TamlCustomNodeFactory;
 
 //-----------------------------------------------------------------------------
 
-void TamlPropertyField::set( const char* pFieldName, const char* pFieldValue )
+void TamlCustomField::set( const char* pFieldName, const char* pFieldValue )
 {
     // Sanity!
     AssertFatal( pFieldName != NULL, "Field name cannot be NULL." );
@@ -61,59 +54,19 @@ void TamlPropertyField::set( const char* pFieldName, const char* pFieldValue )
 #endif
     // Copy field value.
     dStrcpy( mFieldValue, pFieldValue );
-
-    // Reset field object.
-    mpFieldObject = NULL;
-    SAFE_DELETE( mpFieldWriteNode );
 }
 
 //-----------------------------------------------------------------------------
 
-void TamlPropertyField::set( const char* pFieldName, SimObject* pFieldObject )
+void TamlCustomNode::setWriteNode( TamlWriteNode* pWriteNode )
 {
     // Sanity!
-    AssertFatal( pFieldName != NULL, "Field name cannot be NULL." );
-    AssertFatal( pFieldObject != NULL, "Field object cannot be NULL." );
-    AssertFatal( mpFieldWriteNode == NULL, "Field write node must be NULL." );
-
-    // Set field name.
-    mFieldName = StringTable->insert( pFieldName );
-
-    mpFieldObject = pFieldObject;
-    SAFE_DELETE( mpFieldWriteNode );
-
-    // Reset field value.
-    *mFieldValue = 0;
-}
-
-//-----------------------------------------------------------------------------
-
-void TamlPropertyField::setWriteNode( TamlWriteNode* pWriteNode )
-{
-    // Sanity!
-    AssertFatal( mFieldName != StringTable->EmptyString, "Cannot set write node with an empty field name." );
+    AssertFatal( mNodeName != StringTable->EmptyString, "Cannot set write node with an empty node name." );
     AssertFatal( pWriteNode != NULL, "Write node cannot be NULL." );
-    AssertFatal( pWriteNode->mpSimObject == mpFieldObject, "Write node does not match existing field object." );
-    AssertFatal( mpFieldWriteNode == NULL, "Field write node must be NULL." );
-
-    // Set field object.
-    mpFieldWriteNode = pWriteNode;
-
-    // Reset field value.
-    *mFieldValue = 0;
-}
-
-//-----------------------------------------------------------------------------
+    AssertFatal( pWriteNode->mpSimObject == mpProxyObject, "Write node does not match existing proxy object." );
+    AssertFatal( mpProxyWriteNode == NULL, "Field write node must be NULL." );
 
-SimObject* TamlPropertyField::getFieldObject( void ) const
-{
-    return mpFieldObject != NULL ? mpFieldObject : NULL;
-}
-
-//-----------------------------------------------------------------------------
-
-bool TamlPropertyField::isObjectField( void ) const
-{
-    return mpFieldObject != NULL;
+    // Set proxy write node.
+    mpProxyWriteNode = pWriteNode;
 }
 

+ 353 - 254
engine/source/persistence/taml/tamlCustom.h

@@ -51,28 +51,29 @@
 
 //-----------------------------------------------------------------------------
 
-#define MAX_TAML_PROPERTY_FIELDVALUE_LENGTH 2048
+#define MAX_TAML_NODE_FIELDVALUE_LENGTH 2048
 
 //-----------------------------------------------------------------------------
 
 class TamlWriteNode;
+class TamlCustomNode;
+class TamlCustomField;
+extern FactoryCache<TamlCustomNode> TamlCustomNodeFactory;
+extern FactoryCache<TamlCustomField> TamlCustomFieldFactory;
+typedef Vector<TamlCustomNode*> TamlCustomNodeVector;
+typedef Vector<TamlCustomField*> TamlCustomFieldVector;
 
 //-----------------------------------------------------------------------------
 
-class TamlPropertyField : public IFactoryObjectReset
+class TamlCustomField : public IFactoryObjectReset
 {
 public:
-    TamlPropertyField()
+    TamlCustomField()
     {
-        // Reset field object.
-        // NOTE: This MUST be done before the state is reset otherwise we'll be touching uninitialized stuff.
-        mpFieldWriteNode = NULL;
-        mpFieldObject = NULL;
-
         resetState();
     }
 
-    virtual ~TamlPropertyField()
+    virtual ~TamlCustomField()
     {
         // Everything should already be cleared in a state reset.
         // Touching any memory here is dangerous as this type is typically
@@ -80,13 +81,99 @@ public:
         // pretty much anything or everything could be invalid!
     }
 
-    virtual void resetState( void );
+    virtual void resetState( void )
+    {
+        mFieldName = StringTable->EmptyString;
+        *mFieldValue = 0;
+    }
 
     void set( const char* pFieldName, const char* pFieldValue );
 
-    void set( const char* pFieldName, SimObject* pFieldObject );
+    inline void setFieldValue( const char* pFieldName, const ColorI& fieldValue )
+    {
+        // Fetch the field value.
+        const char* pFieldValue = Con::getData( TypeColorI, &const_cast<ColorI&>(fieldValue), 0 );
 
-    void setWriteNode( TamlWriteNode* pWriteNode );
+        // Did we get a field value?
+        if ( pFieldValue == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "Taml: Failed to add node field name '%s' with ColorI value.", pFieldName );
+            pFieldValue = StringTable->EmptyString;
+        }
+
+        set( pFieldName, pFieldValue );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const ColorF& fieldValue )
+    {
+        // Fetch the field value.
+        const char* pFieldValue = Con::getData( TypeColorF, &const_cast<ColorF&>(fieldValue), 0 );
+
+        // Did we get a field value?
+        if ( pFieldValue == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "Taml: Failed to add node field name '%s' with ColorF value.", pFieldName );
+            pFieldValue = StringTable->EmptyString;
+        }
+
+        set( pFieldName, pFieldValue );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const Point2I& fieldValue )
+    {
+        char fieldValueBuffer[32];
+        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d %d", fieldValue.x, fieldValue.y );
+        set( pFieldName, fieldValueBuffer );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const Point2F& fieldValue )
+    {
+        char fieldValueBuffer[32];
+        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g", fieldValue.x, fieldValue.y );
+        set( pFieldName, fieldValueBuffer );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const b2Vec2& fieldValue )
+    {
+        char fieldValueBuffer[32];
+        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %.5g", fieldValue.x, fieldValue.y );
+        set( pFieldName, fieldValueBuffer );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const U32 fieldValue )
+    {
+        char fieldValueBuffer[16];
+        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
+        set( pFieldName, fieldValueBuffer );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const bool fieldValue )
+    {
+        char fieldValueBuffer[16];
+        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
+        set( pFieldName, fieldValueBuffer );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const S32 fieldValue )
+    {
+        char fieldValueBuffer[16];
+        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
+        set( pFieldName, fieldValueBuffer );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const float fieldValue )
+    {
+        char fieldValueBuffer[16];
+        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g", fieldValue );
+        set( pFieldName, fieldValueBuffer );
+    }
+
+    inline void setFieldValue( const char* pFieldName, const char* fieldValue )
+    {
+        set( pFieldName, fieldValue );
+    }
 
     inline void getFieldValue( ColorF& fieldValue ) const
     {
@@ -111,7 +198,7 @@ public:
         if ( dSscanf( mFieldValue, "%d %d", &fieldValue.x, &fieldValue.y ) != 2 )
         {
             // Warn.
-            Con::warnf( "TamlPropertyField - Reading point2I but it has an incorrect format: '%s'.", mFieldValue );
+            Con::warnf( "TamlCustomField - Reading point2I but it has an incorrect format: '%s'.", mFieldValue );
         }
     }
 
@@ -120,7 +207,7 @@ public:
         if ( dSscanf( mFieldValue, "%g %g", &fieldValue.x, &fieldValue.y ) != 2 )
         {
             // Warn.
-            Con::warnf( "TamlPropertyField - Reading point2F but it has an incorrect format: '%s'.", mFieldValue );
+            Con::warnf( "TamlCustomField - Reading point2F but it has an incorrect format: '%s'.", mFieldValue );
         }
     }
 
@@ -129,7 +216,7 @@ public:
         if ( dSscanf( mFieldValue, "%g %g", &fieldValue.x, &fieldValue.y ) != 2 )
         {
             // Warn.
-            Con::warnf( "TamlPropertyField - Reading vector but it has an incorrect format: '%s'.", mFieldValue );
+            Con::warnf( "TamlCustomField - Reading vector but it has an incorrect format: '%s'.", mFieldValue );
         }
     }
 
@@ -158,15 +245,9 @@ public:
         return mFieldValue;
     }
 
-    SimObject* getFieldObject( void ) const;
-
-    inline const TamlWriteNode* getWriteNode( void ) const { return mpFieldWriteNode; }
-
-    bool isObjectField( void ) const;
-
     inline StringTableEntry getFieldName( void ) const { return mFieldName; }
 
-    bool fieldNameBeginsWith( const char* pComparison )
+    bool fieldNameBeginsWith( const char* pComparison ) const
     {
         const U32 comparisonLength = dStrlen( pComparison );
         const U32 fieldNameLength = dStrlen( mFieldName );
@@ -179,7 +260,7 @@ public:
         char fieldNameBuffer[1024];
 
         // Sanity!
-        AssertFatal( fieldNameLength < sizeof(fieldNameBuffer), "TamlPropertyField: Field name is too long." );
+        AssertFatal( fieldNameLength < sizeof(fieldNameBuffer), "TamlCustomField: Field name is too long." );
 
         dStrcpy( fieldNameBuffer, mFieldName );
         fieldNameBuffer[fieldNameLength-1] = 0;
@@ -188,30 +269,29 @@ public:
         return ( fieldName == comparison );
     }
 
+    inline bool isValueEmpty( void ) const { return *mFieldValue == 0; }
+
 private:
     StringTableEntry    mFieldName;
-    char                mFieldValue[MAX_TAML_PROPERTY_FIELDVALUE_LENGTH];
-    SimObject*          mpFieldObject;
-    TamlWriteNode*      mpFieldWriteNode;
+    char                mFieldValue[MAX_TAML_NODE_FIELDVALUE_LENGTH];
 };
 
-static FactoryCache<TamlPropertyField> TamlPropertyFieldFactory;
-
 //-----------------------------------------------------------------------------
 
-typedef Vector<TamlPropertyField*> TamlPropertyFieldVector;
-
-class TamlPropertyAlias :
-    public TamlPropertyFieldVector,
-    public IFactoryObjectReset
+class TamlCustomNode : public IFactoryObjectReset
 {
 public:
-    TamlPropertyAlias()
+    TamlCustomNode()
     {
+        // Reset proxy object.
+        // NOTE: This MUST be done before the state is reset otherwise we'll be touching uninitialized stuff.
+        mpProxyWriteNode = NULL;
+        mpProxyObject = NULL;
+
         resetState();
     }
 
-    virtual ~TamlPropertyAlias()
+    virtual ~TamlCustomNode()
     {
         // Everything should already be cleared in a state reset.
         // Touching any memory here is dangerous as this type is typically
@@ -221,180 +301,174 @@ public:
 
     virtual void resetState( void )
     {
-        while( size() > 0 )
+        // We don't need to delete the write node as it'll get destroyed when the compilation is reset!
+        mpProxyWriteNode = NULL;
+        mpProxyObject = NULL;
+
+        // Cache the children.
+        while ( mChildren.size() > 0 )
+        {
+            TamlCustomNodeFactory.cacheObject( mChildren.back() );
+            mChildren.pop_back();
+        }
+
+        // Cache the fields.
+        while( mFields.size() > 0 )
         {
-            TamlPropertyFieldFactory.cacheObject( back() );
-            pop_back();
+            TamlCustomFieldFactory.cacheObject( mFields.back() );
+            mFields.pop_back();
         }
 
-        mAliasName = StringTable->EmptyString;
+        // Reset the node name.
+        mNodeName = StringTable->EmptyString;
+
+        // Reset node text.
+        mNodeText.resetState();
+
+        // Reset the ignore empty flag.
         mIgnoreEmpty = false;
     }
 
-    void set( const char* pAliasName )
+    inline TamlCustomNode* addNode( SimObject* pProxyObject )
     {
         // Sanity!
-        AssertFatal( pAliasName != NULL, "Type alias cannot be NULL." );
+        AssertFatal( pProxyObject != NULL, "Field object cannot be NULL." );
+        AssertFatal( mpProxyWriteNode == NULL, "Field write node must be NULL." );
+
+        // Create a custom node.
+        TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
 
-        mAliasName = StringTable->insert( pAliasName );
+        // Set node name.
+        pCustomNode->setNodeName( pProxyObject->getClassName() );
+
+        // Set proxy object.
+        pCustomNode->mpProxyObject = pProxyObject;
+
+        // Store node.
+        mChildren.push_back( pCustomNode );
+
+        return pCustomNode;
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const ColorI& fieldValue )
+    inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
     {
-        // Fetch the field value.
-        const char* pFieldValue = Con::getData( TypeColorI, &const_cast<ColorI&>(fieldValue), 0 );
+        // Create a custom node.
+        TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
 
-        // Did we get a field value?
-        if ( pFieldValue == NULL )
-        {
-            // No, so warn.
-            Con::warnf( "Taml: Failed to add property field name '%s' with ColorI value.", pFieldName );
-            pFieldValue = StringTable->EmptyString;
-        }
+        // Fetch node name.
+        pCustomNode->setNodeName( pNodeName );
+
+        // Set ignore-empty flag.
+        pCustomNode->setIgnoreEmpty( ignoreEmpty );
+
+        // Store node.
+        mChildren.push_back( pCustomNode );
 
-        return addField( pFieldName, pFieldValue );
+        return pCustomNode;
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const ColorF& fieldValue )
+    inline void removeNode( const U32 index )
     {
-        // Fetch the field value.
-        const char* pFieldValue = Con::getData( TypeColorF, &const_cast<ColorF&>(fieldValue), 0 );
+        // Sanity!
+        AssertFatal( index < (U32)mChildren.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
 
-        // Did we get a field value?
-        if ( pFieldValue == NULL )
+        // Cache the custom node.
+        TamlCustomNodeFactory.cacheObject( mChildren[index] );
+
+        // Remove it.
+        mChildren.erase( index );
+    }
+
+    inline const TamlCustomNode* findNode( const char* pNodeName ) const
+    {
+        // Sanity!
+        AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
+
+        // Fetch node name.
+        StringTableEntry nodeName = StringTable->insert( pNodeName );
+
+        // Find node.
+        for( Vector<TamlCustomNode*>::const_iterator nodeItr = mChildren.begin(); nodeItr != mChildren.end(); ++nodeItr )
         {
-            // No, so warn.
-            Con::warnf( "Taml: Failed to add property field name '%s' with ColorF value.", pFieldName );
-            pFieldValue = StringTable->EmptyString;
+            if ( (*nodeItr)->getNodeName() == nodeName )
+                return (*nodeItr);
         }
 
-        return addField( pFieldName, pFieldValue );
+        return NULL;
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const Point2I& fieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const ColorI& fieldValue )
     {
-        char fieldValueBuffer[32];
-        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d %d", fieldValue.x, fieldValue.y );
-        return addField( pFieldName, fieldValueBuffer );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const Point2F& fieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const ColorF& fieldValue )
     {
-        char fieldValueBuffer[32];
-        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %0.5g", fieldValue.x, fieldValue.y );
-        return addField( pFieldName, fieldValueBuffer );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const b2Vec2& fieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const Point2I& fieldValue )
     {
-        char fieldValueBuffer[32];
-        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g %.5g", fieldValue.x, fieldValue.y );
-        return addField( pFieldName, fieldValueBuffer );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
+
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const U32 fieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const Point2F& fieldValue )
     {
-        char fieldValueBuffer[16];
-        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
-        return addField( pFieldName, fieldValueBuffer );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const bool fieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const b2Vec2& fieldValue )
     {
-        char fieldValueBuffer[16];
-        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
-        return addField( pFieldName, fieldValueBuffer );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const S32 fieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const U32 fieldValue )
     {
-        char fieldValueBuffer[16];
-        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%d", fieldValue );
-        return addField( pFieldName, fieldValueBuffer );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const float fieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const bool fieldValue )
     {
-        char fieldValueBuffer[16];
-        dSprintf( fieldValueBuffer, sizeof(fieldValueBuffer), "%.5g", fieldValue );
-        return addField( pFieldName, fieldValueBuffer );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    TamlPropertyField* addField( const char* pFieldName, const char* pFieldValue )
+    inline TamlCustomField* addField( const char* pFieldName, const S32 fieldValue )
     {
-        // Create a property field.
-        TamlPropertyField* pPropertyField = TamlPropertyFieldFactory.createObject();
-
-        // Set property field.
-        pPropertyField->set( pFieldName, pFieldValue );
-
-#if TORQUE_DEBUG
-        // Ensure a field name conflict does not exist.
-        for( Vector<TamlPropertyField*>::iterator propertyFieldItr = begin(); propertyFieldItr != end(); ++propertyFieldItr )
-        {
-            // Skip if field name is not the same.
-            if ( pPropertyField->getFieldName() != (*propertyFieldItr)->getFieldName() )
-                continue;
-
-            // Warn!
-            Con::warnf("Conflicting Taml property field name of '%s' in property alias of '%s'.", pFieldName, mAliasName );
-
-            // Cache property field.
-            TamlPropertyFieldFactory.cacheObject( pPropertyField );
-            return NULL;
-        }
-
-        // Ensure the field value is not too long.
-        if ( dStrlen( pFieldValue ) >= MAX_TAML_PROPERTY_FIELDVALUE_LENGTH )
-        {
-            // Warn.
-            Con::warnf("Taml field name '%s' has a field value that is too long (Max:%d): '%s'.",
-                pFieldName,
-                MAX_TAML_PROPERTY_FIELDVALUE_LENGTH,
-                pFieldValue );
-
-            // Cache property field.
-            TamlPropertyFieldFactory.cacheObject( pPropertyField );
-            return NULL;
-        }
-#endif
-        // Store property field.
-        push_back( pPropertyField );
-
-        return pPropertyField;
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    TamlPropertyField* addField( const char* pFieldName, SimObject* pFieldObject )
+    inline TamlCustomField* addField( const char* pFieldName, const float fieldValue )
     {
-        // Create a property field.
-        TamlPropertyField* pPropertyField = TamlPropertyFieldFactory.createObject();
-
-        // Set property field.
-        pPropertyField->set( pFieldName, pFieldObject );
-
-#if TORQUE_DEBUG
-        // Ensure a field name conflict does not exist.
-        for( TamlPropertyFieldVector::iterator propertyFieldItr = begin(); propertyFieldItr != end(); ++propertyFieldItr )
-        {
-            // Skip if field name is not the same.
-            if ( pPropertyField->getFieldName() != (*propertyFieldItr)->getFieldName() )
-                continue;
-
-            // Warn!
-            Con::warnf("Conflicting Taml property field name of '%s' in property alias of '%s'.", pFieldName, mAliasName );
-
-            // Cache property field.
-            TamlPropertyFieldFactory.cacheObject( pPropertyField );
-            return NULL;
-        }
-#endif
-        // Store property field.
-        push_back( pPropertyField );
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
+    }
 
-        return pPropertyField;
+    inline TamlCustomField* addField( const char* pFieldName, const char* fieldValue )
+    {
+        TamlCustomField* pNodeField = TamlCustomFieldFactory.createObject();
+        pNodeField->setFieldValue( pFieldName, fieldValue );
+        return registerField( pNodeField );
     }
 
-    const TamlPropertyField* findField( const char* pFieldName ) const
+    inline const TamlCustomField* findField( const char* pFieldName ) const
     {
         // Sanity!
         AssertFatal( pFieldName != NULL, "Cannot find Taml field name that is NULL." );
@@ -402,8 +476,8 @@ public:
         // Fetch field name.
         StringTableEntry fieldName = StringTable->insert( pFieldName );
 
-        // Find property field.
-        for( TamlPropertyFieldVector::const_iterator fieldItr = begin(); fieldItr != end(); ++fieldItr )
+        // Find node field.
+        for( TamlCustomFieldVector::const_iterator fieldItr = mFields.begin(); fieldItr != mFields.end(); ++fieldItr )
         {
             if ( (*fieldItr)->getFieldName() == fieldName )
                 return (*fieldItr);
@@ -412,175 +486,200 @@ public:
         return NULL;
     }
 
-    StringTableEntry    mAliasName;
-    bool                mIgnoreEmpty;
-};
+    inline void setNodeName( const char* pNodeName )
+    {
+        // Sanity!
+        AssertFatal( pNodeName != NULL, "Cannot add a NULL node name." );
 
-static FactoryCache<TamlPropertyAlias> TamlPropertyAliasFactory;
+        mNodeName = StringTable->insert( pNodeName );
+    }
 
-//-----------------------------------------------------------------------------
+    inline StringTableEntry getNodeName( void ) const { return mNodeName; }
 
-typedef Vector<TamlPropertyAlias*> TamlPropertyAliasVector;
+    void setWriteNode( TamlWriteNode* pWriteNode );
 
-class TamlCustomProperty :
-    public TamlPropertyAliasVector,
-    public IFactoryObjectReset
-{
-public:
-    TamlCustomProperty()
+    inline void setNodeText( const char* pNodeText )
     {
-    }
+        AssertFatal( dStrlen( pNodeText ) < MAX_TAML_NODE_FIELDVALUE_LENGTH, "Custom node text is too long." );
 
-    virtual ~TamlCustomProperty()
-    {
-        // Everything should already be cleared in a state reset.
-        // Touching any memory here is dangerous as this type is typically
-        // held in a static factory cache until shutdown at which point
-        // pretty much anything or everything could be invalid!
+        mNodeText.set( StringTable->EmptyString, pNodeText );
     }
+    inline const TamlCustomField& getNodeTextField( void ) const { return mNodeText; }
+    inline TamlCustomField& getNodeTextField( void ) { return mNodeText; }
 
-    virtual void resetState( void )
+    inline const Vector<TamlCustomNode*>& getChildren( void ) const { return mChildren; }
+    inline const TamlCustomFieldVector& getFields( void ) const { return mFields; }
+
+    inline bool isProxyObject( void ) const { return mpProxyObject != NULL; }
+    template<typename T> T* getProxyObject( const bool deleteIfNotType ) const
     {
-        while( size() > 0 )
+        // Return nothing if no proxy object.
+        if ( mpProxyObject == NULL )
+            return NULL;
+
+        // Cast object to specified type.
+        T* pTypeCast = dynamic_cast<T*>( mpProxyObject );
+
+        // Destroy the object if not the specified type and requested to do so.
+        if ( deleteIfNotType && pTypeCast == NULL )
         {
-            TamlPropertyAliasFactory.cacheObject( back() );
-            pop_back();
+            mpProxyObject->deleteObject();
+            const_cast<SimObject*>(mpProxyObject) = NULL;
+            return NULL;
         }
-        mIgnoreEmpty = true;
-    }
 
-    void set( const char* pPropertyName )
-    {
-        // Sanity!
-        AssertFatal( pPropertyName != NULL, "TamlCustomProperty::set() - Property name cannot be NULL." );
-
-        mPropertyName = StringTable->insert( pPropertyName );
+        return pTypeCast;
     }
+    inline const TamlWriteNode* getProxyWriteNode( void ) const { return mpProxyWriteNode; }
 
-    TamlPropertyAlias* addAlias( const char* pAliasName, const bool ignoreEmpty = false )
-    {
-        // Create a alias.
-        TamlPropertyAlias* pAlias = TamlPropertyAliasFactory.createObject();
+    inline bool isEmpty( void ) const { return mNodeText.isValueEmpty() && mFields.size() == 0 && mChildren.size() == 0; }
 
-        // Set alias name.
-        pAlias->set( pAliasName );
+    inline void setIgnoreEmpty( const bool ignoreEmpty ) { mIgnoreEmpty = ignoreEmpty; }
+    inline bool getIgnoreEmpty( void ) const { return mIgnoreEmpty; }
 
-        // Set ignore-empty flag.
-        pAlias->mIgnoreEmpty = ignoreEmpty;
+private:
+    inline TamlCustomField* registerField( TamlCustomField* pCustomField )
+    {
+#if TORQUE_DEBUG
+        // Ensure a field name conflict does not exist.
+        for( Vector<TamlCustomField*>::iterator nodeFieldItr = mFields.begin(); nodeFieldItr != mFields.end(); ++nodeFieldItr )
+        {
+            // Skip if field name is not the same.
+            if ( pCustomField->getFieldName() != (*nodeFieldItr)->getFieldName() )
+                continue;
 
-        // Store alias.
-        push_back( pAlias );
+            // Warn!
+            Con::warnf("Conflicting Taml node field name of '%s' in node '%s'.", pCustomField->getFieldName(), mNodeName );
 
-        return pAlias;
-    }
+            // Cache node field.
+            TamlCustomFieldFactory.cacheObject( pCustomField );
+            return NULL;
+        }
 
-    void removeAlias( const U32 index )
-    {
-        // Sanity!
-        AssertFatal( index < (U32)size(), "TamlCustomProperty::removeAlias() - Index is out of bounds." );
+        // Ensure the field value is not too long.
+        if ( dStrlen( pCustomField->getFieldValue() ) >= MAX_TAML_NODE_FIELDVALUE_LENGTH )
+        {
+            // Warn.
+            Con::warnf("Taml field name '%s' has a field value that is too long (Max:%d): '%s'.",
+                pCustomField->getFieldName(),
+                MAX_TAML_NODE_FIELDVALUE_LENGTH,
+                pCustomField->getFieldValue() );
 
-        // Cache the alias.
-        TamlPropertyAliasFactory.cacheObject( at(index) );
+            // Cache node field.
+            TamlCustomFieldFactory.cacheObject( pCustomField );
+            return NULL;
+        }
+#endif
+        // Store node field.
+        mFields.push_back( pCustomField );
 
-        // Remove it.
-        erase( index );
+        return pCustomField;
     }
 
-    StringTableEntry mPropertyName;
-    bool mIgnoreEmpty;
-};
+    inline TamlCustomField* createField( void ) const { return TamlCustomFieldFactory.createObject(); }
 
-static FactoryCache<TamlCustomProperty> TamlCustomPropertyFactory;
+private:
+    StringTableEntry        mNodeName;
+    TamlCustomField         mNodeText;
+    Vector<TamlCustomNode*> mChildren;
+    TamlCustomFieldVector   mFields;
+    bool                    mIgnoreEmpty;
+
+    SimObject*              mpProxyObject;
+    TamlWriteNode*          mpProxyWriteNode;
+};
 
 //-----------------------------------------------------------------------------
 
-typedef Vector<TamlCustomProperty*> TamlCustomPropertyVector;
-
-class TamlCustomProperties :
-    public TamlCustomPropertyVector,
-    public IFactoryObjectReset
+class TamlCustomNodes : public IFactoryObjectReset
 {
 public:
-    TamlCustomProperties()
+    TamlCustomNodes()
     {
     }
 
-    virtual ~TamlCustomProperties()
+    virtual ~TamlCustomNodes()
     {
         resetState();
     }
 
     virtual void resetState( void )
     {
-        while( size() > 0 )
+        // Cache the nodes.
+        while ( mNodes.size() > 0 )
         {
-            TamlCustomPropertyFactory.cacheObject( back() );
-            pop_back();
+            TamlCustomNodeFactory.cacheObject( mNodes.back() );
+            mNodes.pop_back();
         }
     }
 
-    TamlCustomProperty* addProperty( const char* pPropertyName, const bool ignoreEmpty = true )
+    inline TamlCustomNode* addNode( const char* pNodeName, const bool ignoreEmpty = true )
     {
-        // Create a custom property.
-        TamlCustomProperty* pCustomProperty = TamlCustomPropertyFactory.createObject();
+        // Create a custom node.
+        TamlCustomNode* pCustomNode = TamlCustomNodeFactory.createObject();
 
-        // Set property name.
-        pCustomProperty->set( pPropertyName );
+        // Set node name.
+        pCustomNode->setNodeName( pNodeName );
 
         // Set ignore-empty flag.
-        pCustomProperty->mIgnoreEmpty = ignoreEmpty;
+        pCustomNode->setIgnoreEmpty( ignoreEmpty );
 
 #if TORQUE_DEBUG
-        // Ensure an property name conflict does not exist.
-        for( TamlCustomPropertyVector::iterator propertyItr = begin(); propertyItr != end(); ++propertyItr )
+        // Ensure a node name conflict does not exist.
+        for( TamlCustomNodeVector::iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
         {
-            // Skip if property name is not the same.
-            if ( pCustomProperty->mPropertyName != (*propertyItr)->mPropertyName )
+            // Skip if node name is not the same.
+            if ( pCustomNode->getNodeName() != (*nodeItr)->getNodeName() )
                 continue;
 
             // Warn!
-            Con::warnf("Conflicting Taml custom property name of '%s'.", pPropertyName );
+            Con::warnf("Conflicting Taml custom node name of '%s'.", pNodeName );
 
-            // Cache property.
-            TamlCustomPropertyFactory.cacheObject( pCustomProperty );
+            // Cache node.
+            TamlCustomNodeFactory.cacheObject( pCustomNode );
             return NULL;
         }
 #endif
-        // Store property.
-        push_back( pCustomProperty );
+        // Store node.
+        mNodes.push_back( pCustomNode );
 
-        return pCustomProperty;
+        return pCustomNode;
     }
 
-    void removeProperty( const U32 index )
+    inline void removeNode( const U32 index )
     {
         // Sanity!
-        AssertFatal( index < (U32)size(), "TamlCustomProperty::removeProperty() - Index is out of bounds." );
+        AssertFatal( index < (U32)mNodes.size(), "tamlCustomNode::removeNode() - Index is out of bounds." );
 
-        // Cache the custom property.
-        TamlCustomPropertyFactory.cacheObject( at(index) );
+        // Cache the custom node.
+        TamlCustomNodeFactory.cacheObject( mNodes[index] );
 
         // Remove it.
-        erase( index );
+        mNodes.erase( index );
     }
 
-    const TamlCustomProperty* findProperty( const char* pPropertyName ) const
+    inline const TamlCustomNode* findNode( const char* pNodeName ) const
     {
         // Sanity!
-        AssertFatal( pPropertyName != NULL, "Cannot find Taml property name that is NULL." );
+        AssertFatal( pNodeName != NULL, "Cannot find Taml node name that is NULL." );
 
-        // Fetch property name.
-        StringTableEntry propertyName = StringTable->insert( pPropertyName );
+        // Fetch node name.
+        StringTableEntry nodeName = StringTable->insert( pNodeName );
 
-        // Find property.
-        for( Vector<TamlCustomProperty*>::const_iterator propertyItr = begin(); propertyItr != end(); ++propertyItr )
+        // Find node.
+        for( Vector<TamlCustomNode*>::const_iterator nodeItr = mNodes.begin(); nodeItr != mNodes.end(); ++nodeItr )
         {
-            if ( (*propertyItr)->mPropertyName == propertyName )
-                return (*propertyItr);
+            if ( (*nodeItr)->getNodeName() == nodeName )
+                return (*nodeItr);
         }
 
         return NULL;
     }
+
+    inline const TamlCustomNodeVector& getNodes( void ) const { return mNodes; }
+
+private:
+    TamlCustomNodeVector mNodes;
 };
 
 #endif // _TAML_CUSTOM_H_

+ 2 - 2
engine/source/persistence/taml/tamlWriteNode.cc

@@ -61,6 +61,6 @@ void TamlWriteNode::resetNode( void )
     // Reset callbacks.
     mpTamlCallbacks = NULL;
 
-    // Reset custom properties.
-    mCustomProperties.resetState();
+    // Reset custom nodes.
+    mCustomNodes.resetState();
 }

+ 1 - 3
engine/source/persistence/taml/tamlWriteNode.h

@@ -67,7 +67,6 @@ public:
     {
         // NOTE: This MUST be done before the state is reset otherwise we'll be touching uninitialized stuff.
         mRefToNode = NULL;
-        mRefField = StringTable->EmptyString;
         mChildren = NULL;
         mpSimObject = NULL;
         mpTamlCallbacks = NULL;
@@ -107,13 +106,12 @@ public:
 
     U32                         mRefId;
     TamlWriteNode*              mRefToNode;
-    StringTableEntry            mRefField;
     SimObject*                  mpSimObject;
     TamlCallbacks*              mpTamlCallbacks;
     const char*                 mpObjectName;
     Vector<TamlWriteNode::FieldValuePair*> mFields;
     Vector<TamlWriteNode*>*     mChildren;
-    TamlCustomProperties        mCustomProperties;
+    TamlCustomNodes             mCustomNodes;
 };
 
 #endif // _TAML_WRITE_NODE_H_

+ 98 - 78
engine/source/persistence/taml/tamlXmlReader.cc

@@ -166,7 +166,7 @@ SimObject* TamlXmlReader::parseElement( TiXmlElement* pXmlElement )
     // Fetch any children.
     TiXmlNode* pChildXmlNode = pXmlElement->FirstChild();
 
-    TamlCustomProperties customProperties;
+    TamlCustomNodes customProperties;
 
     // Do we have any element children?
     if ( pChildXmlNode != NULL )
@@ -247,102 +247,91 @@ SimObject* TamlXmlReader::parseElement( TiXmlElement* pXmlElement )
 
 //-----------------------------------------------------------------------------
 
-void TamlXmlReader::parseCustomElement( TiXmlElement* pXmlElement, TamlCustomProperties& customProperties )
+void TamlXmlReader::parseAttributes( TiXmlElement* pXmlElement, SimObject* pSimObject )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(TamlXmlReader_ParseCustomElement);
-
-    // Is this a standard child element?
-    const char* pPeriod = dStrchr( pXmlElement->Value(), '.' );
+    PROFILE_SCOPE(TamlXmlReader_ParseAttributes);
 
     // Sanity!
-    AssertFatal( pPeriod != NULL, "Parsing extended element but no period character found." );
-
-    // Fetch any property alias.
-    TiXmlNode* pPropertyAliasXmlNode = pXmlElement->FirstChild();
+    AssertFatal( pSimObject != NULL, "Taml: Cannot parse attributes on a NULL object." );
 
-    // Do we have any property alias?
-    if ( pPropertyAliasXmlNode != NULL )
+    // Iterate attributes.
+    for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
     {
-        // Yes, so add custom property.
-        TamlCustomProperty* pCustomProperty = customProperties.addProperty( pPeriod+1 );
-
-        do
-        {
-            // Fetch element.
-            TiXmlElement* pPropertyAliasXmlElement = dynamic_cast<TiXmlElement*>( pPropertyAliasXmlNode );
-
-            // Move to next sibling.
-            pPropertyAliasXmlNode = pPropertyAliasXmlNode->NextSibling();
+        // Insert attribute name.
+        StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
 
-            // Skip if this is not an element?
-            if ( pPropertyAliasXmlElement == NULL )
+        // Ignore if this is a Taml attribute.
+        if (    attributeName == mTamlRefId ||
+                attributeName == mTamlRefToId ||
+                attributeName == mTamlObjectName ||
+                attributeName == mTamlRefField )
                 continue;
 
-            // Add property alias.
-            TamlPropertyAlias* pPropertyAlias = pCustomProperty->addAlias( pPropertyAliasXmlElement->Value() );
+        // We can assume this is a field for now.
+        pSimObject->setPrefixedDataField( attributeName, NULL, pAttribute->Value() );
+    }
+}
 
-            // Iterate property field attributes.
-            for ( TiXmlAttribute* pAttribute = pPropertyAliasXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
-            {
-                // Insert attribute name.
-                StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
+//-----------------------------------------------------------------------------
 
-                // Add property field.
-                pPropertyAlias->addField( attributeName, pAttribute->Value() );
-            }
+void TamlXmlReader::parseCustomElement( TiXmlElement* pXmlElement, TamlCustomNodes& customNodes )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(TamlXmlReader_ParseCustomElement);
 
-            // Fetch any children.
-            TiXmlNode* pChildXmlNode = pPropertyAliasXmlElement->FirstChild();
+    // Is this a standard child element?
+    const char* pPeriod = dStrchr( pXmlElement->Value(), '.' );
 
-            // Do we have any element children?
-            if ( pChildXmlNode != NULL )
-            {
-                do
-                {
-                    // Fetch element.
-                    TiXmlElement* pChildXmlElement = dynamic_cast<TiXmlElement*>( pChildXmlNode );
+    // Sanity!
+    AssertFatal( pPeriod != NULL, "Parsing extended element but no period character found." );
 
-                    // Move to next sibling.
-                    pChildXmlNode = pChildXmlNode->NextSibling();
+    // Fetch any custom XML node.
+    TiXmlNode* pCustomXmlNode = pXmlElement->FirstChild();
 
-                    // Skip if this is not an element?
-                    if ( pChildXmlElement == NULL )
-                        continue;
+    // Finish is no XML node exists.
+    if ( pCustomXmlNode == NULL )
+        return;
 
-                    // Fetch the reference field.
-                    const char* pRefField = getTamlRefField( pChildXmlElement );
+    // Yes, so add custom node.
+    TamlCustomNode* pCustomNode = customNodes.addNode( pPeriod+1 );
 
-                    // Was a reference field found?
-                    if ( pRefField == NULL )
-                    {
-                        // No, so warn.
-                        Con::warnf( "Taml: Encountered a child element in a custom element but it did not have a field reference using '%s'.", mTamlRefField );
-                        continue;
-                    }
+    do
+    {
+        // Fetch element.
+        TiXmlElement* pCustomXmlElement = dynamic_cast<TiXmlElement*>( pCustomXmlNode );
 
-                    // Parse the child element.
-                    SimObject* pFieldObject = parseElement( pChildXmlElement );
+        // Move to next sibling.
+        pCustomXmlNode = pCustomXmlNode->NextSibling();
 
-                    // Add property field.
-                    pPropertyAlias->addField( pRefField, pFieldObject );
-                }
-                while( pChildXmlNode != NULL );
-            }
-        }
-        while ( pPropertyAliasXmlNode != NULL );
+        // Skip if this is not an element.
+        if ( pCustomXmlElement == NULL )
+            continue;
+
+        // Parse custom node.
+        parseCustomNode( pCustomXmlElement, pCustomNode );
     }
+    while ( pCustomXmlNode != NULL );
 }
 
 //-----------------------------------------------------------------------------
 
-void TamlXmlReader::parseAttributes( TiXmlElement* pXmlElement, SimObject* pSimObject )
+void TamlXmlReader::parseCustomNode( TiXmlElement* pXmlElement, TamlCustomNode* pCustomNode )
 {
-    // Debug Profiling.
-    PROFILE_SCOPE(TamlXmlReader_ParseAttributes);
+    // Is the node a proxy object?
+    if (  getTamlRefId( pXmlElement ) != 0 || getTamlRefToId( pXmlElement ) != 0 )
+    {
+        // Yes, so parse proxy object.
+        SimObject* pProxyObject = parseElement( pXmlElement );
 
-    // Sanity!
-    AssertFatal( pSimObject != NULL, "Taml: Cannot parse attributes on a NULL object." );
+        // Add child node.
+        pCustomNode->addNode( pProxyObject );
+
+        return;
+    }
+
+    // Yes, so add child node.
+    TamlCustomNode* pChildNode = pCustomNode->addNode( pXmlElement->Value() );
 
     // Iterate attributes.
     for ( TiXmlAttribute* pAttribute = pXmlElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->Next() )
@@ -350,15 +339,46 @@ void TamlXmlReader::parseAttributes( TiXmlElement* pXmlElement, SimObject* pSimO
         // Insert attribute name.
         StringTableEntry attributeName = StringTable->insert( pAttribute->Name() );
 
-        // Ignore if this is a Taml attribute.
-        if (    attributeName == mTamlRefId ||
-                attributeName == mTamlRefToId ||
-                attributeName == mTamlObjectName ||
-                attributeName == mTamlRefField )
+        // Skip if a Taml reference attribute.
+        if ( attributeName == mTamlRefId || attributeName == mTamlRefToId )
+            continue;
+
+        // Add node field.
+        pChildNode->addField( attributeName, pAttribute->Value() );
+    }
+
+    // Fetch any element text.
+    const char* pElementText = pXmlElement->GetText();
+
+    // Do we have any element text?
+    if ( pElementText != NULL )
+    {
+        // Yes, so store it.
+        pChildNode->setNodeText( pElementText );
+    }
+
+    // Fetch any children.
+    TiXmlNode* pChildXmlNode = pXmlElement->FirstChild();
+
+    // Do we have any element children?
+    if ( pChildXmlNode != NULL )
+    {
+        do
+        {
+            // Yes, so fetch child element.
+            TiXmlElement* pChildXmlElement = dynamic_cast<TiXmlElement*>( pChildXmlNode );
+
+            // Move to next sibling.
+            pChildXmlNode = pChildXmlNode->NextSibling();
+
+            // Skip if this is not an element.
+            if ( pChildXmlElement == NULL )
                 continue;
 
-        // We can assume this is a field for now.
-        pSimObject->setPrefixedDataField( attributeName, NULL, pAttribute->Value() );
+            // Parse custom node.
+            parseCustomNode( pChildXmlElement, pChildNode );
+        }
+        while( pChildXmlNode != NULL );
     }
 }
 

+ 2 - 1
engine/source/persistence/taml/tamlXmlReader.h

@@ -69,8 +69,9 @@ private:
     void resetParse( void );
 
     SimObject* parseElement( TiXmlElement* pXmlElement );
-    void parseCustomElement( TiXmlElement* pXmlElement, TamlCustomProperties& customProperties );
     void parseAttributes( TiXmlElement* pXmlElement, SimObject* pSimObject );
+    void parseCustomElement( TiXmlElement* pXmlElement, TamlCustomNodes& pCustomNode );
+    void parseCustomNode( TiXmlElement* pXmlElement, TamlCustomNode* pCustomNode );
 
     U32 getTamlRefId( TiXmlElement* pXmlElement );
     U32 getTamlRefToId( TiXmlElement* pXmlElement );

+ 107 - 73
engine/source/persistence/taml/tamlXmlWriter.cc

@@ -80,24 +80,10 @@ TiXmlNode* TamlXmlWriter::compileElement( const TamlWriteNode* pTamlWriteNode )
         // Set reference to Id attribute.
         pElement->SetAttribute( TAML_REFID_ATTRIBUTE_NAME, referenceToId );
 
-        // Do we have a reference field?
-        if ( pTamlWriteNode->mRefField != StringTable->EmptyString )
-        {
-            // Yes, so set attribute.
-            pElement->SetAttribute( TAML_REF_FIELD_NAME, pTamlWriteNode->mRefField );
-        }
-
         // Finish because we're a reference to another object.
         return pElement;
     }
 
-    // Do we have a reference field?
-    if ( pTamlWriteNode->mRefField != StringTable->EmptyString )
-    {
-        // Yes, so set attribute.
-        pElement->SetAttribute( TAML_REF_FIELD_NAME, pTamlWriteNode->mRefField );
-    }
-
     // Fetch object name.
     const char* pObjectName = pTamlWriteNode->mpObjectName;
 
@@ -133,70 +119,75 @@ TiXmlNode* TamlXmlWriter::compileElement( const TamlWriteNode* pTamlWriteNode )
 
 //-----------------------------------------------------------------------------
 
+void TamlXmlWriter::compileAttributes( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(TamlXmlWriter_CompileAttributes);
+
+    // Fetch fields.
+    const Vector<TamlWriteNode::FieldValuePair*>& fields = pTamlWriteNode->mFields;
+
+    // Ignore if no fields.
+    if ( fields.size() == 0 )
+        return;
+
+    // Iterate fields.
+    for( Vector<TamlWriteNode::FieldValuePair*>::const_iterator itr = fields.begin(); itr != fields.end(); ++itr )
+    {
+        // Fetch field/value pair.
+        TamlWriteNode::FieldValuePair* pFieldValue = (*itr);
+
+        // Set field attribute.
+        pXmlElement->SetAttribute( pFieldValue->mName, pFieldValue->mpValue );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
 void TamlXmlWriter::compileCustomElements( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode )
 {
     // Debug Profiling.
     PROFILE_SCOPE(TamlXmlWriter_CompileCustomElements);
 
-    // Fetch custom properties.
-    const TamlCustomProperties& customProperties = pTamlWriteNode->mCustomProperties;
+    // Fetch custom nodes.
+    const TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes;
 
-    // Finish if no custom properties exist.
-    if ( customProperties.size() == 0 )
+    // Fetch custom nodes.
+    const TamlCustomNodeVector& nodes = customNodes.getNodes();
+
+    // Finish if no custom nodes to process.
+    if ( nodes.size() == 0 )
         return;
 
-    // Iterate custom properties.
-    for( TamlCustomProperties::const_iterator customPropertyItr = customProperties.begin(); customPropertyItr != customProperties.end(); ++customPropertyItr )
+    // Iterate custom nodes.
+    for( TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr )
     {
-        // Fetch custom property.
-        TamlCustomProperty* pCustomProperty = *customPropertyItr;
+        // Fetch the custom node.
+        TamlCustomNode* pCustomNode = *customNodesItr;
 
         // Format extended element name.
         char extendedElementNameBuffer[256];
-        dSprintf( extendedElementNameBuffer, sizeof(extendedElementNameBuffer), "%s.%s", pXmlElement->Value(), pCustomProperty->mPropertyName );
+        dSprintf( extendedElementNameBuffer, sizeof(extendedElementNameBuffer), "%s.%s", pXmlElement->Value(), pCustomNode->getNodeName() );
         StringTableEntry extendedElementName = StringTable->insert( extendedElementNameBuffer );
 
         // Create element.
         TiXmlElement* pExtendedPropertyElement = new TiXmlElement( extendedElementName );
 
-        // Iterate property alias.
-        for( TamlCustomProperty::const_iterator propertyAliasItr = pCustomProperty->begin(); propertyAliasItr != pCustomProperty->end(); ++propertyAliasItr )
+        // Fetch node children.
+        const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren();
+
+        // Iterate children nodes.
+        for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr )
         {
-            // Fetch property alias.
-            TamlPropertyAlias* pPropertyAlias = *propertyAliasItr;
-
-            // Skip if the alias is set to ignore no properties and there are none.
-            if ( pPropertyAlias->mIgnoreEmpty && pPropertyAlias->size() == 0 )
-                continue;
-
-            // Create element.
-            TiXmlElement* pPropertyElement = new TiXmlElement( pPropertyAlias->mAliasName );
-
-            // Iterate property fields.
-            for ( TamlPropertyAlias::const_iterator propertyFieldItr = pPropertyAlias->begin(); propertyFieldItr != pPropertyAlias->end(); ++propertyFieldItr )
-            {
-                // Fetch property field.
-                TamlPropertyField* pPropertyField = *propertyFieldItr;
-
-                // Is it an object field?
-                if ( pPropertyField->isObjectField() )
-                {
-                    // Yes, so write child element.
-                    pPropertyElement->LinkEndChild( compileElement( pPropertyField->getWriteNode() ) );
-                }
-                else
-                {
-                    // No, so set property attribute.
-                    pPropertyElement->SetAttribute( pPropertyField->getFieldName(), pPropertyField->getFieldValue() );
-                }
-            }
-
-            // Write property element as child.
-            pExtendedPropertyElement->LinkEndChild( pPropertyElement );
+            // Fetch child node.
+            const TamlCustomNode* pChildNode = *childNodeItr;
+
+            // Compile the custom node.
+            compileCustomNode( pExtendedPropertyElement, pChildNode );
         }
 
-        // Is the custom property set to ignore no alias' and there are none.
-        if ( pCustomProperty->mIgnoreEmpty && pExtendedPropertyElement->NoChildren() )
+        // Finish if the node is set to ignore if empty and it is empty.
+        if ( pCustomNode->getIgnoreEmpty() && pExtendedPropertyElement->NoChildren() )
         {
             // Yes, so delete the extended element.
             delete pExtendedPropertyElement;
@@ -204,7 +195,7 @@ void TamlXmlWriter::compileCustomElements( TiXmlElement* pXmlElement, const Taml
         }
         else
         {
-            // No, so write the extended property element as child.
+            // No, so add elementt as child.
             pXmlElement->LinkEndChild( pExtendedPropertyElement );
         }
     }
@@ -212,25 +203,68 @@ void TamlXmlWriter::compileCustomElements( TiXmlElement* pXmlElement, const Taml
 
 //-----------------------------------------------------------------------------
 
-void TamlXmlWriter::compileAttributes( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode )
+void TamlXmlWriter::compileCustomNode( TiXmlElement* pXmlElement, const TamlCustomNode* pCustomNode )
 {
-    // Debug Profiling.
-    PROFILE_SCOPE(TamlXmlWriter_CompileAttributes);
+    // Finish if the node is set to ignore if empty and it is empty.
+    if ( pCustomNode->getIgnoreEmpty() && pCustomNode->isEmpty() )
+        return;
 
-    // Fetch fields.
-    const Vector<TamlWriteNode::FieldValuePair*>& fields = pTamlWriteNode->mFields;
+    // Create element.
+    TiXmlElement* pNodeElement = new TiXmlElement( pCustomNode->getNodeName() );
 
-    // Ignore if no fields.
-    if ( fields.size() == 0 )
-        return;
+    // Is there any node text?
+    if ( !pCustomNode->getNodeTextField().isValueEmpty() )
+    {
+        // Yes, so add a text node.
+        pNodeElement->LinkEndChild( new TiXmlText( pCustomNode->getNodeTextField().getFieldValue() ) );
+    }
+
+    // Fetch fields.
+    const TamlCustomFieldVector& fields = pCustomNode->getFields();
 
     // Iterate fields.
-    for( Vector<TamlWriteNode::FieldValuePair*>::const_iterator itr = fields.begin(); itr != fields.end(); ++itr )
+    for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
     {
-        // Fetch field/value pair.
-        TamlWriteNode::FieldValuePair* pFieldValue = (*itr);
+        // Fetch field.
+        const TamlCustomField* pField = *fieldItr;
 
-        // Set field attribute.
-        pXmlElement->SetAttribute( pFieldValue->mName, pFieldValue->mpValue );
+        // Set field.
+        pNodeElement->SetAttribute( pField->getFieldName(), pField->getFieldValue() );
     }
-}
+
+    // Fetch node children.
+    const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren();
+
+    // Iterate children nodes.
+    for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr )
+    {
+        // Fetch child node.
+        const TamlCustomNode* pChildNode = *childNodeItr;
+
+        // Is the node a proxy object?
+        if ( pChildNode->isProxyObject() )
+        {
+            // Yes, so write the proxy object.
+            pNodeElement->LinkEndChild( compileElement( pChildNode->getProxyWriteNode() ) );
+            continue;
+        }
+        else
+        {
+            // No, so compile the child node.
+            compileCustomNode( pNodeElement, pChildNode );
+        }
+    }
+
+    // Finish if the node is set to ignore if empty and it is empty (including fields).
+    if ( pCustomNode->getIgnoreEmpty() && fields.size() == 0 && pNodeElement->NoChildren() )
+    {
+        // Yes, so delete the extended element.
+        delete pNodeElement;
+        pNodeElement = NULL;
+    }
+    else
+    {
+        // Add node element as child.
+        pXmlElement->LinkEndChild( pNodeElement );
+    }
+}

+ 2 - 1
engine/source/persistence/taml/tamlXmlWriter.h

@@ -51,8 +51,9 @@ private:
 
 private:
     TiXmlNode* compileElement( const TamlWriteNode* pTamlWriteNode );
-    void compileCustomElements( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode );
     void compileAttributes( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode );
+    void compileCustomElements( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode );
+    void compileCustomNode( TiXmlElement* pXmlElement, const TamlCustomNode* pCustomNode );
 };
 
 #endif // _TAML_XMLWRITER_H_

+ 3 - 3
engine/source/sim/simObject.h

@@ -321,10 +321,10 @@ protected:
     virtual void onTamlPreWrite( void ) {}
     virtual void onTamlPostWrite( void ) {}
     virtual void onTamlPreRead( void ) {}
-    virtual void onTamlPostRead( const TamlCustomProperties& customProperties ) {}
+    virtual void onTamlPostRead( const TamlCustomNodes& customNodes ) {}
     virtual void onTamlAddParent( SimObject* pParentObject ) {}
-    virtual void onTamlCustomWrite( TamlCustomProperties& customProperties ) {}
-    virtual void onTamlCustomRead( const TamlCustomProperties& customProperties ) {}
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes ) {}
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes ) {}
     
 protected:
     bool	mCanSaveFieldDictionary; ///< true if dynamic fields (added at runtime) should be saved, defaults to true

+ 7 - 2
modules/ToyAssets/1/assets/particles/bonfire.asset.taml

@@ -26,8 +26,13 @@
 				Keys="0 0" />				
             <FixedForceVariation
                 Keys="0 0" />				
-            <SizeXLife
-                Keys="0 0 0.2 1 0.5 1 0.9 1 1 0" />
+            <SizeXLife>
+				<Key Time="0" Value="0"/>
+				<Key Time="0.2" Value="1"/>
+				<Key Time="0.5" Value="1"/>
+				<Key Time="0.9" Value="1"/>
+				<Key Time="1" Value="0"/>
+			</SizeXLife>
             <SizeXVariation
                 Keys="0 0.3" />				
             <SpinVariation

Some files were not shown because too many files changed in this diff