Browse Source

Merge branch 'development' of https://github.com/GarageGames/Torque3D into ColorPickerAdvanced

Azaezel 9 years ago
parent
commit
ca2ffea6cd
100 changed files with 9355 additions and 437 deletions
  1. 2 0
      CMakeLists.txt
  2. 1 1
      Engine/lib/collada/src/dae/daeStringTable.cpp
  3. 5 1
      Engine/lib/convexDecomp/NvRemoveTjunctions.cpp
  4. 4 4
      Engine/lib/convexDecomp/NvSimpleTypes.h
  5. 1 1
      Engine/lib/libvorbis/lib/codebook.c
  6. 38 13
      Engine/lib/tinyxml/tinyxml.h
  7. 0 23
      Engine/lib/tinyxml/tinyxmlparser.cpp
  8. 17 17
      Engine/source/T3D/aiPlayer.cpp
  9. 3 1
      Engine/source/T3D/aiPlayer.h
  10. 127 0
      Engine/source/T3D/assets/ExampleAsset.cpp
  11. 70 0
      Engine/source/T3D/assets/ExampleAsset.h
  12. 157 0
      Engine/source/T3D/assets/ShapeAsset.cpp
  13. 86 0
      Engine/source/T3D/assets/ShapeAsset.h
  14. 1 1
      Engine/source/T3D/camera.cpp
  15. 1 1
      Engine/source/T3D/camera.h
  16. 1 1
      Engine/source/T3D/convexShape.cpp
  17. 1 0
      Engine/source/T3D/decal/decalData.cpp
  18. 38 8
      Engine/source/T3D/decal/decalManager.cpp
  19. 1 1
      Engine/source/T3D/examples/renderMeshExample.cpp
  20. 7 5
      Engine/source/T3D/fps/guiClockHud.cpp
  21. 7 5
      Engine/source/T3D/fps/guiHealthTextHud.cpp
  22. 7 5
      Engine/source/T3D/fps/guiShapeNameHud.cpp
  23. 2 2
      Engine/source/T3D/fx/fxFoliageReplicator.cpp
  24. 2 2
      Engine/source/T3D/fx/fxFoliageReplicator.h
  25. 1 1
      Engine/source/T3D/fx/precipitation.cpp
  26. 14 1
      Engine/source/T3D/gameFunctions.cpp
  27. 0 8
      Engine/source/T3D/gameTSCtrl.cpp
  28. 0 10
      Engine/source/T3D/gameTSCtrl.h
  29. 3 2
      Engine/source/T3D/lightAnimData.cpp
  30. 9 1
      Engine/source/T3D/lightBase.cpp
  31. 2 1
      Engine/source/T3D/lightBase.h
  32. 10 0
      Engine/source/T3D/lightDescription.cpp
  33. 2 0
      Engine/source/T3D/lightDescription.h
  34. 7 6
      Engine/source/T3D/physics/bullet/btPlayer.cpp
  35. 4 4
      Engine/source/T3D/player.cpp
  36. 1 1
      Engine/source/T3D/player.h
  37. 2 0
      Engine/source/T3D/pointLight.cpp
  38. 43 44
      Engine/source/T3D/shapeBase.cpp
  39. 6 5
      Engine/source/T3D/shapeBase.h
  40. 2 0
      Engine/source/T3D/spotLight.cpp
  41. 1 1
      Engine/source/T3D/trigger.cpp
  42. 5 5
      Engine/source/T3D/trigger.h
  43. 67 5
      Engine/source/T3D/tsStatic.cpp
  44. 9 0
      Engine/source/T3D/tsStatic.h
  45. 9 10
      Engine/source/T3D/turret/turretShape.cpp
  46. 25 15
      Engine/source/app/mainLoop.cpp
  47. 1 19
      Engine/source/app/version.cpp
  48. 352 0
      Engine/source/assets/assetBase.cpp
  49. 145 0
      Engine/source/assets/assetBase.h
  50. 41 0
      Engine/source/assets/assetBase_ScriptBinding.h
  51. 102 0
      Engine/source/assets/assetDefinition.h
  52. 114 0
      Engine/source/assets/assetFieldTypes.cpp
  53. 56 0
      Engine/source/assets/assetFieldTypes.h
  54. 3017 0
      Engine/source/assets/assetManager.cpp
  55. 395 0
      Engine/source/assets/assetManager.h
  56. 811 0
      Engine/source/assets/assetManager_ScriptBinding.h
  57. 184 0
      Engine/source/assets/assetPtr.h
  58. 121 0
      Engine/source/assets/assetQuery.cpp
  59. 90 0
      Engine/source/assets/assetQuery.h
  60. 85 0
      Engine/source/assets/assetQuery_ScriptBinding.h
  61. 564 0
      Engine/source/assets/assetTagsManifest.cpp
  62. 148 0
      Engine/source/assets/assetTagsManifest.h
  63. 151 0
      Engine/source/assets/assetTagsManifest_ScriptBinding.h
  64. 12 0
      Engine/source/assets/core.h
  65. 45 0
      Engine/source/assets/declaredAssets.cpp
  66. 73 0
      Engine/source/assets/declaredAssets.h
  67. 45 0
      Engine/source/assets/referencedAssets.cpp
  68. 73 0
      Engine/source/assets/referencedAssets.h
  69. 132 0
      Engine/source/assets/tamlAssetDeclaredUpdateVisitor.h
  70. 189 0
      Engine/source/assets/tamlAssetDeclaredVisitor.h
  71. 127 0
      Engine/source/assets/tamlAssetReferencedUpdateVisitor.h
  72. 96 0
      Engine/source/assets/tamlAssetReferencedVisitor.h
  73. 1 1
      Engine/source/collision/boxConvex.cpp
  74. 1 1
      Engine/source/console/arrayObject.cpp
  75. 0 4
      Engine/source/console/astNodes.cpp
  76. 12 4
      Engine/source/console/compiledEval.cpp
  77. 1 1
      Engine/source/console/compiler.h
  78. 488 0
      Engine/source/console/console.cpp
  79. 27 3
      Engine/source/console/console.h
  80. 7 10
      Engine/source/console/consoleFunctions.cpp
  81. 146 43
      Engine/source/console/consoleObject.cpp
  82. 187 59
      Engine/source/console/consoleObject.h
  83. 12 15
      Engine/source/console/consoleParser.cpp
  84. 25 25
      Engine/source/console/consoleTypes.cpp
  85. 1 5
      Engine/source/console/consoleTypes.h
  86. 18 1
      Engine/source/console/dynamicTypes.h
  87. 1 1
      Engine/source/console/engineDoc.cpp
  88. 4 0
      Engine/source/console/engineFunctions.h
  89. 9 9
      Engine/source/console/enginePrimitives.h
  90. 6 6
      Engine/source/console/engineStructs.h
  91. 3 3
      Engine/source/console/engineTypeInfo.h
  92. 47 1
      Engine/source/console/engineTypes.h
  93. 1 1
      Engine/source/console/fieldBrushObject.cpp
  94. 9 9
      Engine/source/console/fileSystemFunctions.cpp
  95. 21 0
      Engine/source/console/runtimeClassRep.h
  96. 5 0
      Engine/source/console/scriptFilename.cpp
  97. 1 1
      Engine/source/console/sim.h
  98. 1 1
      Engine/source/console/simFieldDictionary.h
  99. 306 1
      Engine/source/console/simObject.cpp
  100. 45 1
      Engine/source/console/simObject.h

+ 2 - 0
CMakeLists.txt

@@ -2,6 +2,8 @@ cmake_minimum_required (VERSION 2.8.12)
 
 set(TORQUE_APP_NAME "" CACHE STRING "the app name")
 
+set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/temp" CACHE PATH "default install path" FORCE )
+
 if("${TORQUE_APP_NAME}" STREQUAL "")
 	message(FATAL_ERROR "Please set TORQUE_APP_NAME first")
 endif()

+ 1 - 1
Engine/lib/collada/src/dae/daeStringTable.cpp

@@ -58,7 +58,7 @@ void daeStringTable::clear()
 {
 	unsigned int i;
 	for (i=0;i<_stringBuffersList.getCount();i++)
-#if _MSC_VER <= 1200
+#if defined(_MSC_VER) && (_MSC_VER <= 1200)
 		delete [] (char *) _stringBuffersList[i];
 #else
 		delete [] _stringBuffersList[i];

+ 5 - 1
Engine/lib/convexDecomp/NvRemoveTjunctions.cpp

@@ -60,8 +60,12 @@ NvRemoveTjunctions.cpp : A code snippet to remove tjunctions from a triangle mes
 #include <vector>
 #ifdef __APPLE__
    #include <ext/hash_map>
-#else
+#elif LINUX
    #include <hash_map>
+#elif _MSC_VER < 1500
+   #include <hash_map>
+#elif _MSC_VER > 1800
+   #include <unordered_map>
 #endif
 #include "NvUserMemAlloc.h"
 #include "NvHashMap.h"

+ 4 - 4
Engine/lib/convexDecomp/NvSimpleTypes.h

@@ -87,7 +87,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 		
-#elif LINUX
+#elif defined(LINUX)
 	typedef long long			NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;
@@ -101,7 +101,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 
-#elif __APPLE__
+#elif defined(__APPLE__)
 	typedef long long			NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;
@@ -115,7 +115,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 
-#elif __CELLOS_LV2__
+#elif defined(__CELLOS_LV2__)
 	typedef long long			NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;
@@ -129,7 +129,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 
-#elif _XBOX
+#elif defined(_XBOX)
 	typedef __int64				NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;

+ 1 - 1
Engine/lib/libvorbis/lib/codebook.c

@@ -450,7 +450,7 @@ long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){
       }
     }
   }else{
-    int i,j;
+    int i;
 
     for(i=0;i<n;){
       a[i++]=0.f;

+ 38 - 13
Engine/lib/tinyxml/tinyxml.h

@@ -283,10 +283,9 @@ public:
 		TIXML_ERROR_STRING_COUNT
 	};
 
-protected:
-
 	static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
 
+protected:
 	inline static bool IsWhiteSpace( char c )		
 	{ 
 		return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); 
@@ -360,6 +359,7 @@ protected:
 		}
 	}
 
+public:
 	// Return true if the next characters in the stream are any of the endTag sequences.
 	// Ignore case only works for english, and should only be relied on when comparing
 	// to English words: StringEqual( p, "version", true ) is fine.
@@ -368,6 +368,7 @@ protected:
 								bool ignoreCase,
 								TiXmlEncoding encoding );
 
+protected:
 	static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
 
 	TiXmlCursor location;
@@ -375,10 +376,13 @@ protected:
     /// Field containing a generic user pointer
 	void*			userData;
 	
+public:
 	// None of these methods are reliable for any language except English.
 	// Good for approximation, not great for accuracy.
 	static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
 	static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
+
+protected:
 	inline static int ToLower( int v, TiXmlEncoding encoding )
 	{
 		if ( encoding == TIXML_ENCODING_UTF8 )
@@ -750,9 +754,10 @@ protected:
 	#endif
 
 	// Figure out what is at *p, and parse it. Returns null if it is not an xml node.
-	TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
-
+	virtual TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
+public:
 	TiXmlNode*		parent;
+protected:
 	NodeType		type;
 
 	TiXmlNode*		firstChild;
@@ -1047,7 +1052,7 @@ public:
 	/** Sets an attribute of name to a given value. The attribute
 		will be created if it does not exist, or changed if it does.
 	*/
-	void SetAttribute( const char* name, const char * _value );
+	virtual void SetAttribute( const char* name, const char * _value );
 
     #ifdef TIXML_USE_STL
 	const std::string* Attribute( const std::string& name ) const;
@@ -1067,7 +1072,7 @@ public:
 	/** Sets an attribute of name to a given value. The attribute
 		will be created if it does not exist, or changed if it does.
 	*/
-	void SetAttribute( const char * name, int value );
+	virtual void SetAttribute( const char * name, int value );
 
 	/** Sets an attribute of name to a given value. The attribute
 		will be created if it does not exist, or changed if it does.
@@ -1152,7 +1157,6 @@ protected:
 	*/
 	const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
 
-private:
 	TiXmlAttributeSet attributeSet;
 };
 
@@ -1264,7 +1268,6 @@ protected :
 	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
 	#endif
 
-private:
 	bool cdata;			// true if this should be input and output as a CDATA style text element
 };
 
@@ -1336,8 +1339,6 @@ protected:
 	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
 	#endif
 
-private:
-
 	TIXML_STRING version;
 	TIXML_STRING encoding;
 	TIXML_STRING standalone;
@@ -1416,9 +1417,9 @@ public:
 	/// Save a file using the current document value. Returns true if successful.
 	bool SaveFile() const;
 	/// Load a file using the given filename. Returns true if successful.
-	bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	virtual bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
 	/// Save a file using the given filename. Returns true if successful.
-	bool SaveFile( const char * filename ) const;
+	virtual bool SaveFile( const char * filename ) const;
 	/** Load a file using the given FILE*. Returns true if successful. Note that this method
 		doesn't stream - the entire object pointed at by the FILE*
 		will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
@@ -1543,14 +1544,15 @@ protected :
 	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
 	#endif
 
-private:
 	void CopyTo( TiXmlDocument* target ) const;
 
+private:
 	bool error;
 	int  errorId;
 	TIXML_STRING errorDesc;
 	int tabsize;
 	TiXmlCursor errorLocation;
+protected:
 	bool useMicrosoftBOM;		// the UTF-8 BOM were found when read. Note this, and try to write.
 };
 
@@ -1797,6 +1799,29 @@ private:
 	TIXML_STRING lineBreak;
 };
 
+class TiXmlParsingData
+{
+	friend class TiXmlDocument;
+  public:
+	void Stamp( const char* now, TiXmlEncoding encoding );
+
+	const TiXmlCursor& Cursor() const	{ return cursor; }
+
+  private:
+	// Only used by the document!
+	TiXmlParsingData( const char* start, int _tabsize, int row, int col )
+	{
+		assert( start );
+		stamp = start;
+		tabsize = _tabsize;
+		cursor.row = row;
+		cursor.col = col;
+	}
+
+	TiXmlCursor		cursor;
+	const char*		stamp;
+	int				tabsize;
+};
 
 #ifdef _MSC_VER
 #pragma warning( pop )

+ 0 - 23
Engine/lib/tinyxml/tinyxmlparser.cpp

@@ -168,29 +168,6 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng
 }
 
 
-class TiXmlParsingData
-{
-	friend class TiXmlDocument;
-  public:
-	void Stamp( const char* now, TiXmlEncoding encoding );
-
-	const TiXmlCursor& Cursor() const	{ return cursor; }
-
-  private:
-	// Only used by the document!
-	TiXmlParsingData( const char* start, int _tabsize, int row, int col )
-	{
-		assert( start );
-		stamp = start;
-		tabsize = _tabsize;
-		cursor.row = row;
-		cursor.col = col;
-	}
-
-	TiXmlCursor		cursor;
-	const char*		stamp;
-	int				tabsize;
-};
 
 
 void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )

+ 17 - 17
Engine/source/T3D/aiPlayer.cpp

@@ -259,7 +259,7 @@ void AIPlayer::setAimObject( GameBase *targetObject )
  * @param targetObject The object to target
  * @param offset       The offest from the target location to aim at
  */
-void AIPlayer::setAimObject( GameBase *targetObject, Point3F offset )
+void AIPlayer::setAimObject(GameBase *targetObject, const Point3F& offset)
 {
    mAimObject = targetObject;
    mTargetInLOS = false;
@@ -725,24 +725,20 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
 
    // Create a new path.
    NavPath *path = new NavPath();
-   if(path)
+
+   path->mMesh = getNavMesh();
+   path->mFrom = getPosition();
+   path->mTo = pos;
+   path->mFromSet = path->mToSet = true;
+   path->mAlwaysRender = true;
+   path->mLinkTypes = mLinkTypes;
+   path->mXray = true;
+   // Paths plan automatically upon being registered.
+   if(!path->registerObject())
    {
-      path->mMesh = getNavMesh();
-      path->mFrom = getPosition();
-      path->mTo = pos;
-      path->mFromSet = path->mToSet = true;
-      path->mAlwaysRender = true;
-      path->mLinkTypes = mLinkTypes;
-      path->mXray = true;
-      // Paths plan automatically upon being registered.
-      if(!path->registerObject())
-      {
-         delete path;
-         return false;
-      }
-   }
-   else
+      delete path;
       return false;
+   }
 
    if(path->success())
    {
@@ -831,11 +827,15 @@ void AIPlayer::followObject(SceneObject *obj, F32 radius)
    if(!isServerObject())
       return;
 
+   if ((mFollowData.lastPos - obj->getPosition()).len()<mMoveTolerance)
+      return;
+
    if(setPathDestination(obj->getPosition()))
    {
       clearCover();
       mFollowData.object = obj;
       mFollowData.radius = radius;
+      mFollowData.lastPos = obj->getPosition();
    }
 }
 

+ 3 - 1
Engine/source/T3D/aiPlayer.h

@@ -122,10 +122,12 @@ private:
       SimObjectPtr<SceneObject> object;
       /// Distance at whcih to follow.
       F32 radius;
+      Point3F lastPos;
       /// Default constructor.
       FollowData() : object(NULL)
       {
          radius = 5.0f;
+         lastPos = Point3F::Zero;
       }
    };
 
@@ -161,7 +163,7 @@ public:
 
    // Targeting and aiming sets/gets
    void setAimObject( GameBase *targetObject );
-   void setAimObject( GameBase *targetObject, Point3F offset );
+   void setAimObject(GameBase *targetObject, const Point3F& offset);
    GameBase* getAimObject() const  { return mAimObject; }
    void setAimLocation( const Point3F &location );
    Point3F getAimLocation() const { return mAimLocation; }

+ 127 - 0
Engine/source/T3D/assets/ExampleAsset.cpp

@@ -0,0 +1,127 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _EXAMPLE_ASSET_H_
+#include "ExampleAsset.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assets/assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _TAML_
+#include "persistence/taml/taml.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(ExampleAsset);
+
+ConsoleType(ExampleAssetPtr, TypeExampleAssetPtr, ExampleAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeExampleAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ExampleAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeExampleAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ExampleAsset>* pAssetPtr = dynamic_cast<AssetPtr<ExampleAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ExampleAsset::ExampleAsset() :
+mAcquireReferenceCount(0),
+mpOwningAssetManager(NULL),
+mAssetInitialized(false)
+{
+   // Generate an asset definition.
+   mpAssetDefinition = new AssetDefinition();
+}
+
+//-----------------------------------------------------------------------------
+
+ExampleAsset::~ExampleAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void ExampleAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+}
+
+//------------------------------------------------------------------------------
+
+void ExampleAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}

+ 70 - 0
Engine/source/T3D/assets/ExampleAsset.h

@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#ifndef _EXAMPLE_ASSET_H_
+#define _EXAMPLE_ASSET_H_
+
+#ifndef _ASSET_BASE_H_
+#include "assets/assetBase.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assets/assetDefinition.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+class ExampleAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   AssetManager*           mpOwningAssetManager;
+   bool                    mAssetInitialized;
+   AssetDefinition*        mpAssetDefinition;
+   U32                     mAcquireReferenceCount;
+
+public:
+   ExampleAsset();
+   virtual ~ExampleAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ExampleAsset);
+
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
+};
+
+DefineConsoleType(TypeExampleAssetPtr, ExampleAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 157 - 0
Engine/source/T3D/assets/ShapeAsset.cpp

@@ -0,0 +1,157 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _SHAPE_ASSET_H_
+#include "ShapeAsset.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assets/assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _TAML_
+#include "persistence/taml/taml.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
+#include "core/resourceManager.h"
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+static U32 execDepth = 0;
+static U32 journalDepth = 1;
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(ShapeAsset);
+
+ConsoleType(TestAssetPtr, TypeShapeAssetPtr, ShapeAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeShapeAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ShapeAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeShapeAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ShapeAsset>* pAssetPtr = dynamic_cast<AssetPtr<ShapeAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ShapeAsset::ShapeAsset() :
+mAcquireReferenceCount(0),
+mpOwningAssetManager(NULL),
+mAssetInitialized(false)
+{
+   // Generate an asset definition.
+   mpAssetDefinition = new AssetDefinition();
+}
+
+//-----------------------------------------------------------------------------
+
+ShapeAsset::~ShapeAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void ShapeAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("fileName", TypeFilename, Offset(mFileName, ShapeAsset), "Path to the script file we want to execute");
+}
+
+void ShapeAsset::initializeAsset()
+{
+   // Call parent.
+   Parent::initializeAsset();
+
+   if (dStrcmp(mFileName, "") == 0)
+      return;
+
+   loadShape();
+}
+
+bool ShapeAsset::loadShape()
+{
+   mShape = ResourceManager::get().load(mFileName);
+
+   if (!mShape)
+   {
+      Con::errorf("StaticMesh::updateShape : failed to load shape file!");
+      return false; //if it failed to load, bail out
+   }
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+
+void ShapeAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}

+ 86 - 0
Engine/source/T3D/assets/ShapeAsset.h

@@ -0,0 +1,86 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#ifndef _SHAPE_ASSET_H_
+#define _SHAPE_ASSET_H_
+
+#ifndef _ASSET_BASE_H_
+#include "assets/assetBase.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assets/assetDefinition.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+#ifndef _TSSHAPE_H_
+#include "ts/tsShape.h"
+#endif
+#ifndef __RESOURCE_H__
+#include "core/resource.h"
+#endif
+
+//-----------------------------------------------------------------------------
+class ShapeAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   AssetManager*           mpOwningAssetManager;
+   bool                    mAssetInitialized;
+   AssetDefinition*        mpAssetDefinition;
+   U32                     mAcquireReferenceCount;
+
+protected:
+   StringTableEntry   mFileName;
+   Resource<TSShape>	 mShape;
+
+public:
+   ShapeAsset();
+   virtual ~ShapeAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   virtual void initializeAsset();
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ShapeAsset);
+
+   bool loadShape();
+
+   TSShape* getShape() { return mShape; }
+
+protected:
+   virtual void            onAssetRefresh(void) {}
+};
+
+DefineConsoleType(TypeShapeAssetPtr, ShapeAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 1 - 1
Engine/source/T3D/camera.cpp

@@ -393,7 +393,7 @@ void Camera::getEyeCameraTransform(IDisplayDevice *displayDevice, U32 eyeId, Mat
    }
 }
 
-DisplayPose Camera::calcCameraDeltaPose(GameConnection *con, DisplayPose inPose)
+DisplayPose Camera::calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose)
 {
    // NOTE: this is intended to be similar to updateMove
    DisplayPose outPose;

+ 1 - 1
Engine/source/T3D/camera.h

@@ -237,7 +237,7 @@ class Camera: public ShapeBase
       virtual void interpolateTick( F32 delta);
       virtual void getCameraTransform( F32* pos,MatrixF* mat );
       virtual void getEyeCameraTransform( IDisplayDevice *display, U32 eyeId, MatrixF *outMat );
-      virtual DisplayPose calcCameraDeltaPose(GameConnection *con, DisplayPose inPose);
+      virtual DisplayPose calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose);
 
       virtual void writePacketData( GameConnection* conn, BitStream* stream );
       virtual void readPacketData( GameConnection* conn, BitStream* stream );

+ 1 - 1
Engine/source/T3D/convexShape.cpp

@@ -502,7 +502,7 @@ void ConvexShape::prepRenderImage( SceneRenderState *state )
    }
    */
 
-   if ( mVertexBuffer.isNull() )
+   if ( mVertexBuffer.isNull() || !state)
       return;
 
    // If we don't have a material instance after the override then 

+ 1 - 0
Engine/source/T3D/decal/decalData.cpp

@@ -284,6 +284,7 @@ void DecalData::unpackData( BitStream *stream )
    Parent::unpackData( stream );
 
    stream->read( &lookupName );
+   assignName(lookupName);
    stream->read( &size );  
    stream->read( &materialName );
    _updateMaterial();

+ 38 - 8
Engine/source/T3D/decal/decalManager.cpp

@@ -1235,8 +1235,30 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
          currentBatch = &batches.last();
          currentBatch->startDecal = i;
          currentBatch->decalCount = 1;
-         currentBatch->iCount = decal->mIndxCount;
-         currentBatch->vCount = decal->mVertCount;
+
+         // Shrink and warning: preventing a potential crash.
+         currentBatch->iCount =
+             (decal->mIndxCount > smMaxIndices) ? smMaxIndices : decal->mIndxCount;
+         currentBatch->vCount =
+             (decal->mVertCount > smMaxVerts) ? smMaxVerts : decal->mVertCount;
+#ifdef TORQUE_DEBUG
+         // we didn't mean send a spam to the console
+         static U32 countMsgIndx = 0;
+         if ( (decal->mIndxCount > smMaxIndices) && ((countMsgIndx++ % 1024) == 0) ) {
+            Con::warnf(
+               "DecalManager::prepRenderImage() - Shrinked indices of decal."
+               " Lost %u.",  (decal->mIndxCount - smMaxIndices)
+            );
+         }
+         static U32 countMsgVert = 0;
+         if ( (decal->mVertCount > smMaxVerts) && ((countMsgVert++ % 1024) == 0) ) {
+            Con::warnf(
+               "DecalManager::prepRenderImage() - Shrinked vertices of decal."
+               " Lost %u.",  (decal->mVertCount - smMaxVerts)
+            );
+         }
+#endif
+
          currentBatch->mat = mat;
          currentBatch->matInst = decal->mDataBlock->getMaterialInstance();
          currentBatch->priority = decal->getRenderPriority();         
@@ -1299,15 +1321,21 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
       {
          DecalInstance *dinst = mDecalQueue[j];
 
-         for ( U32 k = 0; k < dinst->mIndxCount; k++ )
+         const U32 indxCount =
+             (dinst->mIndxCount > currentBatch.iCount) ?
+             currentBatch.iCount : dinst->mIndxCount;
+         for ( U32 k = 0; k < indxCount; k++ )
          {
             *( pbPtr + ioffset + k ) = dinst->mIndices[k] + voffset;            
          }
 
-         ioffset += dinst->mIndxCount;
+         ioffset += indxCount;
 
-         dMemcpy( vpPtr + voffset, dinst->mVerts, sizeof( DecalVertex ) * dinst->mVertCount );
-         voffset += dinst->mVertCount;
+         const U32 vertCount =
+             (dinst->mVertCount > currentBatch.vCount) ?
+             currentBatch.vCount : dinst->mVertCount;
+         dMemcpy( vpPtr + voffset, dinst->mVerts, sizeof( DecalVertex ) * vertCount );
+         voffset += vertCount;
 
          // Ugly hack for ProjectedShadow!
          if ( (dinst->mFlags & CustomDecal) && dinst->mCustomTex != NULL )
@@ -1357,8 +1385,10 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
       pb->lock( &pbPtr );
 
       // Memcpy from system to video memory.
-      dMemcpy( vpPtr, vertData, sizeof( DecalVertex ) * currentBatch.vCount );
-      dMemcpy( pbPtr, indexData, sizeof( U16 ) * currentBatch.iCount );
+      const U32 vpCount = sizeof( DecalVertex ) * currentBatch.vCount;
+      dMemcpy( vpPtr, vertData, vpCount );
+      const U32 pbCount = sizeof( U16 ) * currentBatch.iCount;
+      dMemcpy( pbPtr, indexData, pbCount );
 
       pb->unlock();
       vb->unlock();

+ 1 - 1
Engine/source/T3D/examples/renderMeshExample.cpp

@@ -269,7 +269,7 @@ void RenderMeshExample::prepRenderImage( SceneRenderState *state )
       createGeometry();
 
    // If we have no material then skip out.
-   if ( !mMaterialInst )
+   if ( !mMaterialInst || !state)
       return;
 
    // If we don't have a material instance after the override then 

+ 7 - 5
Engine/source/T3D/fps/guiClockHud.cpp

@@ -113,9 +113,11 @@ void GuiClockHud::initPersistFields()
 
 void GuiClockHud::onRender(Point2I offset, const RectI &updateRect)
 {
+   GFXDrawUtil* drawUtil = GFX->getDrawUtil();
+
    // Background first
    if (mShowFill)
-      GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor);
+      drawUtil->drawRectFill(updateRect, mFillColor);
 
    // Convert ms time into hours, minutes and seconds.
    S32 time = S32(getTime());
@@ -129,13 +131,13 @@ void GuiClockHud::onRender(Point2I offset, const RectI &updateRect)
    // Center the text
    offset.x += (getWidth() - mProfile->mFont->getStrWidth((const UTF8 *)buf)) / 2;
    offset.y += (getHeight() - mProfile->mFont->getHeight()) / 2;
-   GFX->getDrawUtil()->setBitmapModulation(mTextColor);
-   GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);
-   GFX->getDrawUtil()->clearBitmapModulation();
+   drawUtil->setBitmapModulation(mTextColor);
+   drawUtil->drawText(mProfile->mFont, offset, buf);
+   drawUtil->clearBitmapModulation();
 
    // Border last
    if (mShowFrame)
-      GFX->getDrawUtil()->drawRect(updateRect, mFrameColor);
+      drawUtil->drawRect(updateRect, mFrameColor);
 }
 
 

+ 7 - 5
Engine/source/T3D/fps/guiHealthTextHud.cpp

@@ -162,10 +162,12 @@ void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect)
       else  
          mValue = 100 - (100 * control->getDamageValue());    
    }  
+
+   GFXDrawUtil* drawUtil = GFX->getDrawUtil();
   
    // If enabled draw background first  
    if (mShowFill)  
-      GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor);  
+      drawUtil->drawRectFill(updateRect, mFillColor);  
   
    // Prepare text and center it  
    S32 val = (S32)mValue;    
@@ -190,11 +192,11 @@ void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect)
       }  
    }  
   
-   GFX->getDrawUtil()->setBitmapModulation(tColor);    
-   GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);    
-   GFX->getDrawUtil()->clearBitmapModulation();    
+   drawUtil->setBitmapModulation(tColor);    
+   drawUtil->drawText(mProfile->mFont, offset, buf);    
+   drawUtil->clearBitmapModulation();    
   
    // If enabled draw the border last  
    if (mShowFrame)  
-      GFX->getDrawUtil()->drawRect(updateRect, mFrameColor);  
+      drawUtil->drawRect(updateRect, mFrameColor);  
 }  

+ 7 - 5
Engine/source/T3D/fps/guiShapeNameHud.cpp

@@ -301,18 +301,20 @@ void GuiShapeNameHud::drawName(Point2I offset, const char *name, F32 opacity)
    offset.x -= width / 2;
    offset.y -= height / 2;
 
+   GFXDrawUtil* drawUtil = GFX->getDrawUtil();
+
    // Background fill first
    if (mShowLabelFill)
-      GFX->getDrawUtil()->drawRectFill(RectI(offset, extent), mLabelFillColor);
+      drawUtil->drawRectFill(RectI(offset, extent), mLabelFillColor);
 
    // Deal with opacity and draw.
    mTextColor.alpha = opacity;
-   GFX->getDrawUtil()->setBitmapModulation(mTextColor);
-   GFX->getDrawUtil()->drawText(mProfile->mFont, offset + mLabelPadding, name);
-   GFX->getDrawUtil()->clearBitmapModulation();
+   drawUtil->setBitmapModulation(mTextColor);
+   drawUtil->drawText(mProfile->mFont, offset + mLabelPadding, name);
+   drawUtil->clearBitmapModulation();
 
    // Border last
    if (mShowLabelFrame)
-      GFX->getDrawUtil()->drawRect(RectI(offset, extent), mLabelFrameColor);
+      drawUtil->drawRect(RectI(offset, extent), mLabelFrameColor);
 }
 

+ 2 - 2
Engine/source/T3D/fx/fxFoliageReplicator.cpp

@@ -248,7 +248,7 @@ fxFoliageCulledList::fxFoliageCulledList(Box3F SearchBox, fxFoliageCulledList* I
 
 //------------------------------------------------------------------------------
 
-void fxFoliageCulledList::FindCandidates(Box3F SearchBox, fxFoliageCulledList* InVec)
+void fxFoliageCulledList::FindCandidates(const Box3F& SearchBox, fxFoliageCulledList* InVec)
 {
    // Search the Culled List.
    for (U32 i = 0; i < InVec->GetListCount(); i++)
@@ -1028,7 +1028,7 @@ void fxFoliageReplicator::SetupBuffers()
 
 //------------------------------------------------------------------------------
 
-Box3F fxFoliageReplicator::FetchQuadrant(Box3F Box, U32 Quadrant)
+Box3F fxFoliageReplicator::FetchQuadrant(const Box3F& Box, U32 Quadrant)
 {
    Box3F QuadrantBox;
 

+ 2 - 2
Engine/source/T3D/fx/fxFoliageReplicator.h

@@ -86,7 +86,7 @@ public:
    fxFoliageCulledList(Box3F SearchBox, fxFoliageCulledList* InVec);
    ~fxFoliageCulledList() {};
 
-   void FindCandidates(Box3F SearchBox, fxFoliageCulledList* InVec);
+   void FindCandidates(const Box3F& SearchBox, fxFoliageCulledList* InVec);
 
    U32 GetListCount(void) { return mCulledObjectSet.size(); };
    fxFoliageItem* GetElement(U32 index) { return mCulledObjectSet[index]; };
@@ -157,7 +157,7 @@ protected:
 
    void SyncFoliageReplicators(void);
 
-   Box3F FetchQuadrant(Box3F Box, U32 Quadrant);
+   Box3F FetchQuadrant(const Box3F& Box, U32 Quadrant);
    void ProcessQuadrant(fxFoliageQuadrantNode* pParentNode, fxFoliageCulledList* pCullList, U32 Quadrant);
    void ProcessNodeChildren(fxFoliageQuadrantNode* pParentNode, fxFoliageCulledList* pCullList);
 

+ 1 - 1
Engine/source/T3D/fx/precipitation.cpp

@@ -1293,7 +1293,7 @@ void Precipitation::interpolateTick(F32 delta)
 void Precipitation::processTick(const Move *)
 {
    //nothing to do on the server
-   if (isServerObject() || mDataBlock == NULL)
+   if (isServerObject() || mDataBlock == NULL || isHidden())
       return;
 
    const U32 currTime = Platform::getVirtualMilliseconds();

+ 14 - 1
Engine/source/T3D/gameFunctions.cpp

@@ -349,7 +349,13 @@ bool GameProcessCameraQuery(CameraQuery *query)
 
       // Provide some default values
       query->projectionOffset = Point2F::Zero;
-
+      query->stereoTargets[0] = 0;
+      query->stereoTargets[1] = 0;
+      query->eyeOffset[0] = Point3F::Zero;
+      query->eyeOffset[1] = Point3F::Zero;
+      query->hasFovPort = false;
+      query->hasStereoTargets = false;
+      
       F32 cameraFov = 0.0f;
       bool fovSet = false;
 
@@ -383,6 +389,7 @@ bool GameProcessCameraQuery(CameraQuery *query)
          {
             display->getFovPorts(query->fovPort);
             fovSet = true;
+            query->hasFovPort = true;
          }
          
          // Grab the latest overriding render view transforms
@@ -390,6 +397,12 @@ bool GameProcessCameraQuery(CameraQuery *query)
 
          display->getStereoViewports(query->stereoViewports);
          display->getStereoTargets(query->stereoTargets);
+         query->hasStereoTargets = true;
+      }
+      else
+      {
+         query->eyeTransforms[0] = query->cameraMatrix;
+         query->eyeTransforms[1] = query->cameraMatrix;
       }
 
       // Use the connection's FOV settings if requried

+ 0 - 8
Engine/source/T3D/gameTSCtrl.cpp

@@ -55,10 +55,6 @@ bool GameTSCtrl::onAdd()
    if ( !Parent::onAdd() )
       return false;
 
-#ifdef TORQUE_DEMO_WATERMARK
-   mWatermark.init();
-#endif
-
    return true;
 }
 
@@ -172,10 +168,6 @@ void GameTSCtrl::onRender(Point2I offset, const RectI &updateRect)
 
    if(!skipRender || true)
       Parent::onRender(offset, updateRect);
-
-#ifdef TORQUE_DEMO_WATERMARK
-   mWatermark.render(getExtent());
-#endif
 }
 
 //--------------------------------------------------------------------------

+ 0 - 10
Engine/source/T3D/gameTSCtrl.h

@@ -30,12 +30,6 @@
 #include "gui/3d/guiTSControl.h"
 #endif
 
-#ifdef TORQUE_DEMO_WATERMARK
-#ifndef _WATERMARK_H_
-#include "demo/watermark/watermark.h"
-#endif
-#endif
-
 class ProjectileData;
 class GameBase;
 
@@ -45,10 +39,6 @@ class GameTSCtrl : public GuiTSCtrl
 private:
    typedef GuiTSCtrl Parent;
 
-#ifdef TORQUE_DEMO_WATERMARK
-   Watermark mWatermark;
-#endif
-
    void makeScriptCall(const char *func, const GuiEvent &evt) const;
 
 public:

+ 3 - 2
Engine/source/T3D/lightAnimData.cpp

@@ -195,6 +195,7 @@ bool LightAnimData::AnimValue<COUNT>::animate( F32 time, F32 *output )
    F32 scaledTime, lerpFactor, valueRange, keyFrameLerp;
    U32 posFrom, posTo;
    S32 keyFrameFrom, keyFrameTo;
+   F32 initialValue = *output;
    
    bool wasAnimated = false;
 
@@ -215,13 +216,13 @@ bool LightAnimData::AnimValue<COUNT>::animate( F32 time, F32 *output )
 	   valueRange = ( value2[i] - value1[i] ) / 25.0f;
 
       if ( !smooth[i] )
-   	   output[i] = value1[i] + ( keyFrameFrom * valueRange );
+         output[i] = (value1[i] + (keyFrameFrom * valueRange)) * initialValue;
       else
       {
          lerpFactor = scaledTime - posFrom;
    	   keyFrameLerp = ( keyFrameTo - keyFrameFrom ) * lerpFactor;
 
-         output[i] = value1[i] + ( ( keyFrameFrom + keyFrameLerp ) * valueRange );
+         output[i] = (value1[i] + ((keyFrameFrom + keyFrameLerp) * valueRange)) * initialValue;
       }
    }
 

+ 9 - 1
Engine/source/T3D/lightBase.cpp

@@ -60,6 +60,8 @@ LightBase::LightBase()
       mColor( ColorF::WHITE ),
       mBrightness( 1.0f ),
       mCastShadows( false ),
+      mStaticRefreshFreq( 250 ),
+      mDynamicRefreshFreq( 8 ),
       mPriority( 1.0f ),
       mAnimationData( NULL ),      
       mFlareData( NULL ),
@@ -90,6 +92,8 @@ void LightBase::initPersistFields()
       addField( "color", TypeColorF, Offset( mColor, LightBase ), "Changes the base color hue of the light." );
       addField( "brightness", TypeF32, Offset( mBrightness, LightBase ), "Adjusts the lights power, 0 being off completely." );      
       addField( "castShadows", TypeBool, Offset( mCastShadows, LightBase ), "Enables/disabled shadow casts by this light." );
+      addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightBase ), "static shadow refresh rate (milliseconds)" );
+      addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightBase ), "dynamic shadow refresh rate (milliseconds)" );
       addField( "priority", TypeF32, Offset( mPriority, LightBase ), "Used for sorting of lights by the light manager. "
 		  "Priority determines if a light has a stronger effect than, those with a lower value" );
 
@@ -277,6 +281,8 @@ U32 LightBase::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
       stream->write( mBrightness );
 
       stream->writeFlag( mCastShadows );
+      stream->write(mStaticRefreshFreq);
+      stream->write(mDynamicRefreshFreq);
 
       stream->write( mPriority );      
 
@@ -322,6 +328,8 @@ void LightBase::unpackUpdate( NetConnection *conn, BitStream *stream )
       stream->read( &mColor );
       stream->read( &mBrightness );      
       mCastShadows = stream->readFlag();
+      stream->read(&mStaticRefreshFreq);
+      stream->read(&mDynamicRefreshFreq);
 
       stream->read( &mPriority );      
       
@@ -431,7 +439,7 @@ DefineConsoleMethod( LightBase, playAnimation, void, (const char * anim), (""),
    "existing one is played."
    "@hide")
 {
-	if ( dStrIsEmpty(anim) )
+	if ( String::isEmpty(anim) )
     {
         object->playAnimation();
         return;

+ 2 - 1
Engine/source/T3D/lightBase.h

@@ -56,7 +56,8 @@ protected:
    F32 mBrightness;
 
    bool mCastShadows;
-
+   S32 mStaticRefreshFreq;
+   S32 mDynamicRefreshFreq;
    F32 mPriority;
 
    LightInfo *mLight;

+ 10 - 0
Engine/source/T3D/lightDescription.cpp

@@ -36,6 +36,8 @@ LightDescription::LightDescription()
    brightness( 1.0f ),
    range( 5.0f ),
    castShadows( false ),
+   mStaticRefreshFreq( 250 ),
+   mDynamicRefreshFreq( 8 ),
    animationData( NULL ),
    animationDataId( 0 ),
    animationPeriod( 1.0f ),
@@ -94,6 +96,8 @@ void LightDescription::initPersistFields()
       addField( "brightness", TypeF32, Offset( brightness, LightDescription ), "Adjusts the lights power, 0 being off completely." );      
       addField( "range", TypeF32, Offset( range, LightDescription ), "Controls the size (radius) of the light" );
       addField( "castShadows", TypeBool, Offset( castShadows, LightDescription ), "Enables/disabled shadow casts by this light." );
+      addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightDescription ), "static shadow refresh rate (milliseconds)" );
+      addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightDescription ), "dynamic shadow refresh rate (milliseconds)" );
 
    endGroup( "Light" );
 
@@ -153,6 +157,8 @@ void LightDescription::packData( BitStream *stream )
    stream->write( brightness );
    stream->write( range );
    stream->writeFlag( castShadows );
+   stream->write(mStaticRefreshFreq);
+   stream->write(mDynamicRefreshFreq);
 
    stream->write( animationPeriod );
    stream->write( animationPhase );
@@ -181,6 +187,8 @@ void LightDescription::unpackData( BitStream *stream )
    stream->read( &brightness );     
    stream->read( &range );
    castShadows = stream->readFlag();
+   stream->read(&mStaticRefreshFreq);
+   stream->read(&mDynamicRefreshFreq);
 
    stream->read( &animationPeriod );
    stream->read( &animationPhase );
@@ -200,6 +208,8 @@ void LightDescription::submitLight( LightState *state, const MatrixF &xfm, Light
    li->setRange( range );
    li->setColor( color );
    li->setCastShadows( castShadows );
+   li->setStaticRefreshFreq(mStaticRefreshFreq);
+   li->setDynamicRefreshFreq(mDynamicRefreshFreq);
    li->setTransform( xfm );
 
    if ( animationData )

+ 2 - 0
Engine/source/T3D/lightDescription.h

@@ -101,6 +101,8 @@ public:
    F32 brightness;
    F32 range;
    bool castShadows;
+   S32 mStaticRefreshFreq;
+   S32 mDynamicRefreshFreq;
 
    LightAnimData *animationData;   
    S32 animationDataId;

+ 7 - 6
Engine/source/T3D/physics/bullet/btPlayer.cpp

@@ -290,8 +290,9 @@ bool BtPlayer::_sweep( btVector3 *inOutCurrPos, const btVector3 &disp, Collision
    BtPlayerSweepCallback callback( mGhostObject, disp.normalized() );
 	callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
 	callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
-	
-	mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
+
+   if (disp.length()>0.0001)
+      mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
 
 	inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
    if ( callback.hasHit() )
@@ -340,7 +341,8 @@ void BtPlayer::_stepForward( btVector3 *inOutCurrPos, const btVector3 &displacem
 		callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
 		callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
-		mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
+      if (disp.length()>0.0001)
+         mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
 
       // Subtract from the travel fraction.
       fraction -= callback.m_closestHitFraction;
@@ -434,9 +436,8 @@ void BtPlayer::findContact(   SceneObject **contactObject,
       if ( other == mGhostObject )
          other = (btCollisionObject*)pair.m_pProxy1->m_clientObject;
 
-      AssertFatal( !outOverlapObjects->contains( PhysicsUserData::getObject( other->getUserPointer() ) ),
-         "Got multiple pairs of the same object!" );
-      outOverlapObjects->push_back( PhysicsUserData::getObject( other->getUserPointer() ) );
+      if (!outOverlapObjects->contains(PhysicsUserData::getObject(other->getUserPointer())))
+         outOverlapObjects->push_back( PhysicsUserData::getObject( other->getUserPointer() ) );
 
       if ( other->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
          continue;

+ 4 - 4
Engine/source/T3D/player.cpp

@@ -4659,9 +4659,9 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
       }
       Point3F distance = end - start;
 
-      if (mFabs(distance.x) < mObjBox.len_x() &&
-          mFabs(distance.y) < mObjBox.len_y() &&
-          mFabs(distance.z) < mObjBox.len_z())
+      if (mFabs(distance.x) < mScaledBox.len_x() &&
+          mFabs(distance.y) < mScaledBox.len_y() &&
+          mFabs(distance.z) < mScaledBox.len_z())
       {
          // We can potentially early out of this.  If there are no polys in the clipped polylist at our
          //  end position, then we can bail, and just set start = end;
@@ -5586,7 +5586,7 @@ void Player::getMuzzleTransform(U32 imageSlot,MatrixF* mat)
    *mat = nmat;
 }
 
-DisplayPose Player::calcCameraDeltaPose(GameConnection *con, DisplayPose inPose)
+DisplayPose Player::calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose)
 {
    // NOTE: this is intended to be similar to updateMove
    DisplayPose outPose;

+ 1 - 1
Engine/source/T3D/player.h

@@ -684,7 +684,7 @@ public:
    void getEyeBaseTransform(MatrixF* mat, bool includeBank);
    void getRenderEyeTransform(MatrixF* mat);
    void getRenderEyeBaseTransform(MatrixF* mat, bool includeBank);
-   virtual DisplayPose calcCameraDeltaPose(GameConnection *con, DisplayPose inPose);
+   virtual DisplayPose calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose);
    void getCameraParameters(F32 *min, F32 *max, Point3F *offset, MatrixF *rot);
    void getMuzzleTransform(U32 imageSlot,MatrixF* mat);
    void getRenderMuzzleTransform(U32 imageSlot,MatrixF* mat);   

+ 2 - 0
Engine/source/T3D/pointLight.cpp

@@ -116,6 +116,8 @@ void PointLight::_conformLights()
 
    mLight->setBrightness( mBrightness );
    mLight->setCastShadows( mCastShadows );
+   mLight->setStaticRefreshFreq(mStaticRefreshFreq);
+   mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
    mLight->setPriority( mPriority );
 
    // Update the bounds and scale to fit our light.

+ 43 - 44
Engine/source/T3D/shapeBase.cpp

@@ -40,7 +40,6 @@
 #include "scene/sceneRenderState.h"
 #include "scene/sceneObjectLightingPlugin.h"
 #include "T3D/fx/explosion.h"
-#include "T3D/fx/particleEmitter.h"
 #include "T3D/fx/cameraFXMgr.h"
 #include "environment/waterBlock.h"
 #include "T3D/debris.h"
@@ -154,19 +153,26 @@ ShapeBaseData::ShapeBaseData()
    shadowSphereAdjust( 1.0f ),
    shapeName( StringTable->insert("") ),
    cloakTexName( StringTable->insert("") ),
+   cubeDescId( 0 ),
+   reflectorDesc( NULL ),
+   debris( NULL ),
+   debrisID( 0 ),
+   debrisShapeName( StringTable->insert("") ),
+   explosion( NULL ),
+   explosionID( 0 ),
+   underwaterExplosion( NULL ),
+   underwaterExplosionID( 0 ),
    mass( 1.0f ),
    drag( 0.0f ),
    density( 1.0f ),
    maxEnergy( 0.0f ),
    maxDamage( 1.0f ),
-   disabledLevel( 1.0f ),
    destroyedLevel( 1.0f ),
+   disabledLevel( 1.0f ),
    repairRate( 0.0033f ),
    eyeNode( -1 ),
    earNode( -1 ),
    cameraNode( -1 ),
-   damageSequence( -1 ),
-   hulkSequence( -1 ),
    cameraMaxDist( 0.0f ),
    cameraMinDist( 0.2f ),
    cameraDefaultFov( 75.0f ),
@@ -174,24 +180,17 @@ ShapeBaseData::ShapeBaseData()
    cameraMaxFov( 120.f ),
    cameraCanBank( false ),
    mountedImagesBank( false ),
-   isInvincible( false ),
-   renderWhenDestroyed( true ),
-   debris( NULL ),
-   debrisID( 0 ),
-   debrisShapeName( StringTable->insert("") ),
-   explosion( NULL ),
-   explosionID( 0 ),
-   underwaterExplosion( NULL ),
-   underwaterExplosionID( 0 ),
+   debrisDetail( -1 ),
+   damageSequence( -1 ),
+   hulkSequence( -1 ),
+   observeThroughObject( false ),
    firstPersonOnly( false ),
    useEyePoint( false ),
-   cubeDescId( 0 ),
-   reflectorDesc( NULL ),
-   observeThroughObject( false ),
+   isInvincible( false ),
+   renderWhenDestroyed( true ),
    computeCRC( false ),
    inheritEnergyFromMount( false ),
-   mCRC( 0 ),
-   debrisDetail( -1 )
+   mCRC( 0 )
 {      
    dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints );
 }
@@ -878,46 +877,46 @@ IMPLEMENT_CALLBACK( ShapeBase, validateCameraFov, F32, (F32 fov), (fov),
    "@see ShapeBaseData\n\n");
 
 ShapeBase::ShapeBase()
- : mDrag( 0.0f ),
-   mBuoyancy( 0.0f ),
-   mWaterCoverage( 0.0f ),
-   mLiquidHeight( 0.0f ),
+ : mDataBlock( NULL ),
+   mIsAiControlled( false ),
    mControllingObject( NULL ),
-   mGravityMod( 1.0f ),
-   mAppliedForce( Point3F::Zero ),
-   mTimeoutList( NULL ),
-   mDataBlock( NULL ),
+   mMoveMotion( false ),
+   mShapeBaseMount( NULL ),
    mShapeInstance( NULL ),
+   mConvexList( new Convex ),
    mEnergy( 0.0f ),
    mRechargeRate( 0.0f ),
+   mMass( 1.0f ),
+   mOneOverMass( 1.0f ),
+   mDrag( 0.0f ),
+   mBuoyancy( 0.0f ),
+   mLiquidHeight( 0.0f ),
+   mWaterCoverage( 0.0f ),
+   mAppliedForce( Point3F::Zero ),
+   mGravityMod( 1.0f ),
+   mDamageFlash( 0.0f ),
+   mWhiteOut( 0.0f ),
+   mFlipFadeVal( false ),
+   mTimeoutList( NULL ),
    mDamage( 0.0f ),
    mRepairRate( 0.0f ),
    mRepairReserve( 0.0f ),
    mDamageState( Enabled ),
    mDamageThread( NULL ),
    mHulkThread( NULL ),
-   mLastRenderFrame( 0 ),
-   mLastRenderDistance( 0.0f ),
+   damageDir( 0.0f, 0.0f, 1.0f ),
    mCloaked( false ),
    mCloakLevel( 0.0f ),
-   mDamageFlash( 0.0f ),
-   mWhiteOut( 0.0f ),
-   mIsControlled( false ),
-   mConvexList( new Convex ),
-   mCameraFov( 90.0f ),
    mFadeOut( true ),
    mFading( false ),
    mFadeVal( 1.0f ),
-   mFadeTime( 1.0f ),
    mFadeElapsedTime( 0.0f ),
+   mFadeTime( 1.0f ),
    mFadeDelay( 0.0f ),
-   mFlipFadeVal( false ),
-   damageDir( 0.0f, 0.0f, 1.0f ),
-   mShapeBaseMount( NULL ),
-   mMass( 1.0f ),
-   mOneOverMass( 1.0f ),
-   mMoveMotion( false ),
-   mIsAiControlled( false )
+   mCameraFov( 90.0f ),
+   mIsControlled( false ),
+   mLastRenderFrame( 0 ),
+   mLastRenderDistance( 0.0f )
 {
    mTypeMask |= ShapeBaseObjectType | LightObjectType;   
 
@@ -1192,13 +1191,13 @@ void ShapeBase::onDeleteNotify( SimObject *obj )
    Parent::onDeleteNotify( obj );      
 }
 
-void ShapeBase::onImpact(SceneObject* obj, VectorF vec)
+void ShapeBase::onImpact(SceneObject* obj, const VectorF& vec)
 {
    if (!isGhost())
       mDataBlock->onImpact_callback( this, obj, vec, vec.len() );
 }
 
-void ShapeBase::onImpact(VectorF vec)
+void ShapeBase::onImpact(const VectorF& vec)
 {
    if (!isGhost())
       mDataBlock->onImpact_callback( this, NULL, vec, vec.len() );
@@ -1995,7 +1994,7 @@ void ShapeBase::getEyeCameraTransform(IDisplayDevice *displayDevice, U32 eyeId,
    *outMat = temp;
 }
 
-DisplayPose ShapeBase::calcCameraDeltaPose(GameConnection *con, DisplayPose inPose)
+DisplayPose ShapeBase::calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose)
 {
    // NOTE: this is intended to be similar to updateMove
    // WARNING: does not take into account any move values

+ 6 - 5
Engine/source/T3D/shapeBase.h

@@ -63,14 +63,15 @@
    #include "console/dynamicTypes.h"
 #endif
 
+// Need full definition visible for SimObjectPtr<ParticleEmitter>
+#include "T3D/fx/particleEmitter.h"
+
 class GFXCubemap;
 class TSShapeInstance;
 class SceneRenderState;
 class TSThread;
 class GameConnection;
 struct CameraScopeQuery;
-class ParticleEmitter;
-class ParticleEmitterData;
 class ProjectileData;
 class ExplosionData;
 struct DebrisData;
@@ -1103,8 +1104,8 @@ protected:
    virtual void shakeCamera( U32 imageSlot );
    virtual void updateDamageLevel();
    virtual void updateDamageState();
-   virtual void onImpact(SceneObject* obj, VectorF vec);
-   virtual void onImpact(VectorF vec);
+   virtual void onImpact(SceneObject* obj, const VectorF& vec);
+   virtual void onImpact(const VectorF& vec);
    /// @}
 
    /// The inner prep render function that does the 
@@ -1587,7 +1588,7 @@ public:
    virtual void getEyeCameraTransform( IDisplayDevice *display, U32 eyeId, MatrixF *outMat );
 
    /// Calculates a delta camera angle and view position based on inPose
-   virtual DisplayPose calcCameraDeltaPose(GameConnection *con, DisplayPose inPose);
+   virtual DisplayPose calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose);
 
    /// Gets the index of a node inside a mounted image given the name
    /// @param   imageSlot   Image slot

+ 2 - 0
Engine/source/T3D/spotLight.cpp

@@ -122,6 +122,8 @@ void SpotLight::_conformLights()
    mLight->setColor( mColor );
    mLight->setBrightness( mBrightness );
    mLight->setCastShadows( mCastShadows );
+   mLight->setStaticRefreshFreq(mStaticRefreshFreq);
+   mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
    mLight->setPriority( mPriority );
 
    mOuterConeAngle = getMax( 0.01f, mOuterConeAngle );

+ 1 - 1
Engine/source/T3D/trigger.cpp

@@ -236,7 +236,7 @@ DECLARE_STRUCT( Polyhedron );
 IMPLEMENT_STRUCT( Polyhedron, Polyhedron,,
    "" )
 END_IMPLEMENT_STRUCT;
-ConsoleType( floatList, TypeTriggerPolyhedron, Polyhedron )
+ConsoleType(floatList, TypeTriggerPolyhedron, Polyhedron, "")
 
 
 ConsoleGetType( TypeTriggerPolyhedron )

+ 5 - 5
Engine/source/T3D/trigger.h

@@ -87,6 +87,10 @@ class Trigger : public GameBase
    String            mLeaveCommand;
    String            mTickCommand;
 
+   static const U32 CMD_SIZE = 1024;
+
+  protected:
+   
    enum TriggerUpdateBits
    {
       TransformMask = Parent::NextFreeMask << 0,
@@ -97,10 +101,6 @@ class Trigger : public GameBase
       NextFreeMask  = Parent::NextFreeMask << 5,
    };
 
-   static const U32 CMD_SIZE = 1024;
-
-  protected:
-
    static bool smRenderTriggers;
    bool testObject(GameBase* enter);
    void processTick(const Move *move);
@@ -142,7 +142,7 @@ class Trigger : public GameBase
    // Trigger
    void setTriggerPolyhedron(const Polyhedron&);
 
-   void      potentialEnterObject(GameBase*);
+   virtual void potentialEnterObject(GameBase*);
    U32       getNumTriggeringObjects() const;
    GameBase* getObject(const U32);   
    const Vector<GameBase*>& getObjects() const { return mObjects; }

+ 67 - 5
Engine/source/T3D/tsStatic.cpp

@@ -91,6 +91,9 @@ ConsoleDocClass( TSStatic,
 );
 
 TSStatic::TSStatic()
+:
+   cubeDescId( 0 ),
+   reflectorDesc( NULL )
 {
    mNetFlags.set(Ghostable | ScopeAlways);
 
@@ -102,7 +105,7 @@ TSStatic::TSStatic()
    mPlayAmbient      = true;
    mAmbientThread    = NULL;
 
-   mAllowPlayerStep = true;
+   mAllowPlayerStep = false;
 
    mConvexList = new Convex;
 
@@ -186,6 +189,11 @@ void TSStatic::initPersistFields()
 
    endGroup("Rendering");
 
+   addGroup( "Reflection" );
+      addField( "cubeReflectorDesc", TypeRealString, Offset( cubeDescName, TSStatic ), 
+         "References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n");
+   endGroup( "Reflection" );
+
    addGroup("Collision");
 
       addField( "collisionType",    TypeTSMeshType,   Offset( mCollisionType,   TSStatic ),
@@ -292,6 +300,14 @@ bool TSStatic::onAdd()
 
    addToScene();
 
+   if ( isClientObject() )
+   {      
+      mCubeReflector.unregisterReflector();
+
+      if ( reflectorDesc )
+         mCubeReflector.registerReflector( this, reflectorDesc );      
+   }
+
    _updateShouldTick();
 
    // Accumulation
@@ -357,6 +373,16 @@ bool TSStatic::_createShape()
    if ( mAmbientThread )
       mShapeInstance->setSequence( mAmbientThread, ambientSeq, 0);
 
+   // Resolve CubeReflectorDesc.
+   if ( cubeDescName.isNotEmpty() )
+   {
+      Sim::findObject( cubeDescName, reflectorDesc );
+   }
+   else if( cubeDescId > 0 )
+   {
+      Sim::findObject( cubeDescId, reflectorDesc );
+   }
+
    return true;
 }
 
@@ -429,6 +455,8 @@ void TSStatic::onRemove()
    mShapeInstance = NULL;
 
    mAmbientThread = NULL;
+   if ( isClientObject() )
+       mCubeReflector.unregisterReflector();
 
    Parent::onRemove();
 }
@@ -561,6 +589,12 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
 
    F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));   
 
+   // If we're currently rendering our own reflection we
+   // don't want to render ourselves into it.
+   if ( mCubeReflector.isRendering() )
+      return;
+
+
    if ( mForceDetail == -1 )
       mShapeInstance->setDetailFromDistance( state, dist * invScale );
    else
@@ -577,6 +611,9 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
    rdata.setFadeOverride( 1.0f );
    rdata.setOriginSort( mUseOriginSort );
 
+   if ( mCubeReflector.isEnabled() )
+      rdata.setCubemap( mCubeReflector.getCubemap() );
+
    // Acculumation
    rdata.setAccuTex(mAccuTex);
 
@@ -604,6 +641,20 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
    mat.scale( mObjScale );
    GFX->setWorldMatrix( mat );
 
+   if ( state->isDiffusePass() && mCubeReflector.isEnabled() && mCubeReflector.getOcclusionQuery() )
+   {
+       RenderPassManager *pass = state->getRenderPass();
+       OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>();  
+       
+       ri->type = RenderPassManager::RIT_Occluder;
+       ri->query = mCubeReflector.getOcclusionQuery();
+       mObjToWorld.mulP( mObjBox.getCenter(), &ri->position );
+       ri->scale.set( mObjBox.getExtents() );
+       ri->orientation = pass->allocUniqueXform( mObjToWorld ); 
+       ri->isSphere = false;
+       state->getRenderPass()->addInst( ri );
+   }
+
    mShapeInstance->animate();
    if(mShapeInstance)
    {
@@ -715,6 +766,10 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
    if ( mLightPlugin )
       retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
 
+   if( stream->writeFlag( reflectorDesc != NULL ) )
+   {
+      stream->writeRangedU32( reflectorDesc->getId(), DataBlockObjectIdFirst,  DataBlockObjectIdLast );
+   }
    return retMask;
 }
 
@@ -782,6 +837,11 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
       mLightPlugin->unpackUpdate(this, con, stream);
    }
 
+   if( stream->readFlag() )
+   {
+      cubeDescId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
+   }
+
    if ( isProperlyAdded() )
       _updateShouldTick();
 }
@@ -1171,8 +1231,10 @@ DefineEngineMethod( TSStatic, changeMaterial, void, ( const char* mapTo, Materia
       return;
    }
 
+   TSMaterialList* shapeMaterialList = object->getShape()->materialList;
+
    // Check the mapTo name exists for this shape
-   S32 matIndex = object->getShape()->materialList->getMaterialNameList().find_next(String(mapTo));
+   S32 matIndex = shapeMaterialList->getMaterialNameList().find_next(String(mapTo));
    if (matIndex < 0)
    {
       Con::errorf("TSShape::changeMaterial failed: Invalid mapTo name '%s'", mapTo);
@@ -1190,13 +1252,13 @@ DefineEngineMethod( TSStatic, changeMaterial, void, ( const char* mapTo, Materia
 
    // Replace instances with the new material being traded in. Lets make sure that we only
    // target the specific targets per inst, this is actually doing more than we thought
-   delete object->getShape()->materialList->mMatInstList[matIndex];
-   object->getShape()->materialList->mMatInstList[matIndex] = newMat->createMatInstance();
+   delete shapeMaterialList->mMatInstList[matIndex];
+   shapeMaterialList->mMatInstList[matIndex] = newMat->createMatInstance();
 
    // Finish up preparing the material instances for rendering
    const GFXVertexFormat *flags = getGFXVertexFormat<GFXVertexPNTTB>();
    FeatureSet features = MATMGR->getDefaultFeatures();
-   object->getShape()->materialList->getMaterialInst(matIndex)->init( features, flags );
+   shapeMaterialList->getMaterialInst(matIndex)->init(features, flags);
 }
 
 DefineEngineMethod( TSStatic, getModelFile, const char *, (),,

+ 9 - 0
Engine/source/T3D/tsStatic.h

@@ -39,6 +39,10 @@
 #include "ts/tsShape.h"
 #endif
 
+#ifndef _REFLECTOR_H_
+   #include "scene/reflector.h"
+#endif
+
 class TSShapeInstance;
 class TSThread;
 class TSStatic;
@@ -147,6 +151,11 @@ protected:
    /// Start or stop processing ticks depending on our state.
    void _updateShouldTick();
 
+   String cubeDescName;
+   U32 cubeDescId;
+   ReflectorDesc *reflectorDesc;
+   CubeReflector mCubeReflector;
+
 protected:
 
    Convex *mConvexList;

+ 9 - 10
Engine/source/T3D/turret/turretShape.cpp

@@ -1059,9 +1059,9 @@ void TurretShape::writePacketData(GameConnection *connection, BitStream *stream)
 {
    // Update client regardless of status flags.
    Parent::writePacketData(connection, stream);
-
-   stream->write(mRot.x);
-   stream->write(mRot.z);
+   
+   stream->writeSignedFloat(mRot.x / M_2PI_F, 7);
+   stream->writeSignedFloat(mRot.z / M_2PI_F, 7);
 }
 
 void TurretShape::readPacketData(GameConnection *connection, BitStream *stream)
@@ -1069,9 +1069,8 @@ void TurretShape::readPacketData(GameConnection *connection, BitStream *stream)
    Parent::readPacketData(connection, stream);
 
    Point3F rot(0.0f, 0.0f, 0.0f);
-   stream->read(&rot.x);
-   stream->read(&rot.z);
-
+   rot.x = stream->readSignedFloat(7) * M_2PI_F;
+   rot.z = stream->readSignedFloat(7) * M_2PI_F;
    _setRotation(rot);
 
    mTurretDelta.rot = rot;
@@ -1100,8 +1099,8 @@ U32 TurretShape::packUpdate(NetConnection *connection, U32 mask, BitStream *stre
 
    if (stream->writeFlag(mask & TurretUpdateMask))
    {
-      stream->write(mRot.x);
-      stream->write(mRot.z);
+      stream->writeSignedFloat(mRot.x / M_2PI_F, 7);
+      stream->writeSignedFloat(mRot.z / M_2PI_F, 7);
       stream->write(allowManualRotation);
       stream->write(allowManualFire);
    }
@@ -1137,8 +1136,8 @@ void TurretShape::unpackUpdate(NetConnection *connection, BitStream *stream)
    if (stream->readFlag())
    {
       Point3F rot(0.0f, 0.0f, 0.0f);
-      stream->read(&rot.x);
-      stream->read(&rot.z);
+      rot.x = stream->readSignedFloat(7) * M_2PI_F;
+      rot.z = stream->readSignedFloat(7) * M_2PI_F;
       _setRotation(rot);
 
       // New delta for client side interpolation

+ 25 - 15
Engine/source/app/mainLoop.cpp

@@ -61,14 +61,18 @@
 // For the TickMs define... fix this for T2D...
 #include "T3D/gameBase/processList.h"
 
-#ifdef TORQUE_DEMO_PURCHASE
-#include "demo/pestTimer/pestTimer.h"
-#endif
-
 #ifdef TORQUE_ENABLE_VFS
 #include "platform/platformVFS.h"
 #endif
 
+#ifndef _MODULE_MANAGER_H
+#include "module/moduleManager.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assets/assetManager.h"
+#endif
+
 DITTS( F32, gTimeScale, 1.0 );
 DITTS( U32, gTimeAdvance, 0 );
 DITTS( U32, gFrameSkip, 0 );
@@ -261,7 +265,7 @@ void StandardMainLoop::init()
 
    // Initialize modules.
    
-   ModuleManager::initializeSystem();
+   EngineModuleManager::initializeSystem();
          
    // Initialise ITickable.
 #ifdef TORQUE_TGB_ONLY
@@ -292,6 +296,15 @@ void StandardMainLoop::init()
 	Con::addVariable("MiniDump::Params", TypeString, &gMiniDumpParams);
 	Con::addVariable("MiniDump::ExecDir", TypeString, &gMiniDumpExecDir);
 #endif
+
+   // Register the module manager.
+   ModuleDatabase.registerObject("ModuleDatabase");
+
+   // Register the asset database.
+   AssetDatabase.registerObject("AssetDatabase");
+
+   // Register the asset database as a module listener.
+   ModuleDatabase.addListener(&AssetDatabase);
    
    ActionMap* globalMap = new ActionMap;
    globalMap->registerObject("GlobalActionMap");
@@ -309,10 +322,6 @@ void StandardMainLoop::init()
    // Hook in for UDP notification
    Net::smPacketReceive.notify(GNet, &NetInterface::processPacketReceiveEvent);
 
-   #ifdef TORQUE_DEMO_PURCHASE
-   PestTimerinit();
-   #endif
-
    #ifdef TORQUE_DEBUG_GUARD
       Memory::flagCurrentAllocs( Memory::FLAG_Static );
    #endif
@@ -325,10 +334,16 @@ void StandardMainLoop::shutdown()
 
    delete tm;
    preShutdown();
+
+   // Unregister the module database.
+   ModuleDatabase.unregisterObject();
+
+   // Unregister the asset database.
+   AssetDatabase.unregisterObject();
    
    // Shut down modules.
    
-   ModuleManager::shutdownSystem();
+   EngineModuleManager::shutdownSystem();
    
    ThreadPool::GlobalThreadPool::deleteSingleton();
 
@@ -613,11 +628,6 @@ bool StandardMainLoop::doMainLoop()
       ThreadPool::processMainThreadWorkItems();
       Sampler::endFrame();
       PROFILE_END_NAMED(MainLoop);
-
-	  #ifdef TORQUE_DEMO_PURCHASE
-	  CheckTimer();
-	  CheckBlocker();
-	  #endif
    }
    
    return keepRunning;

+ 1 - 19
Engine/source/app/version.cpp

@@ -139,22 +139,4 @@ DefineConsoleFunction( getBuildString, const char*, (), , "Get the type of build
 #endif
 }
 
-ConsoleFunctionGroupEnd( CompileInformation );
-
-DefineConsoleFunction( isDemo, bool, (), , "")
-{
-#ifdef TORQUE_DEMO
-   return true;
-#else
-   return false;
-#endif
-}
-
-DefineConsoleFunction( isWebDemo, bool, (), , "")
-{
-#ifdef TORQUE_DEMO
-   return Platform::getWebDeployment();
-#else
-   return false;
-#endif
-}
+ConsoleFunctionGroupEnd( CompileInformation );

+ 352 - 0
Engine/source/assets/assetBase.cpp

@@ -0,0 +1,352 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+// Script bindings.
+#include "assetBase_ScriptBinding.h"
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(AssetBase);
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry assetNameField = StringTable->insert("AssetName");
+StringTableEntry assetDescriptionField = StringTable->insert("AssetDescription");
+StringTableEntry assetCategoryField = StringTable->insert("AssetCategory");
+StringTableEntry assetAutoUnloadField = StringTable->insert("AssetAutoUnload");
+StringTableEntry assetInternalField = StringTable->insert("AssetInternal");
+StringTableEntry assetPrivateField = StringTable->insert("AssetPrivate");
+
+//-----------------------------------------------------------------------------
+
+AssetBase::AssetBase() :
+mAcquireReferenceCount(0),
+mpOwningAssetManager(NULL),
+mAssetInitialized(false)
+{
+   // Generate an asset definition.
+   mpAssetDefinition = new AssetDefinition();
+}
+
+//-----------------------------------------------------------------------------
+
+AssetBase::~AssetBase()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   // Asset configuration.
+   addProtectedField(assetNameField, TypeString, 0, &setAssetName, &getAssetName, &writeAssetName, "The name of the asset.  The is not a unique identification like an asset Id.");
+   addProtectedField(assetDescriptionField, TypeString, 0, &setAssetDescription, &getAssetDescription, &writeAssetDescription, "The simple description of the asset contents.");
+   addProtectedField(assetCategoryField, TypeString, 0, &setAssetCategory, &getAssetCategory, &writeAssetCategory, "An arbitrary category that can be used to categorized assets.");
+   addProtectedField(assetAutoUnloadField, TypeBool, 0, &setAssetAutoUnload, &getAssetAutoUnload, &writeAssetAutoUnload, "Whether the asset is automatically unloaded when an asset is released and has no other acquisitions or not.");
+   addProtectedField(assetInternalField, TypeBool, 0, &setAssetInternal, &getAssetInternal, &writeAssetInternal, "Whether the asset is used internally only or not.");
+   addProtectedField(assetPrivateField, TypeBool, 0, &defaultProtectedNotSetFn, &getAssetPrivate, &defaultProtectedNotWriteFn, "Whether the asset is private or not.");
+}
+
+//------------------------------------------------------------------------------
+
+void AssetBase::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+
+   // Cast to asset.
+   AssetBase* pAsset = static_cast<AssetBase*>(object);
+
+   // Sanity!
+   AssertFatal(pAsset != NULL, "AssetBase::copyTo() - Object is not the correct type.");
+
+   // Copy state.
+   pAsset->setAssetName(getAssetName());
+   pAsset->setAssetDescription(getAssetDescription());
+   pAsset->setAssetCategory(getAssetCategory());
+   pAsset->setAssetAutoUnload(getAssetAutoUnload());
+   pAsset->setAssetInternal(getAssetInternal());
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetDescription(const char* pAssetDescription)
+{
+   // Fetch asset description.
+   StringTableEntry assetDescription = StringTable->insert(pAssetDescription);
+
+   // Ignore no change.
+   if (mpAssetDefinition->mAssetDescription == assetDescription)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetDescription = assetDescription;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetCategory(const char* pAssetCategory)
+{
+   // Fetch asset category.
+   StringTableEntry assetCategory = StringTable->insert(pAssetCategory);
+
+   // Ignore no change.
+   if (mpAssetDefinition->mAssetCategory == assetCategory)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetCategory = assetCategory;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetAutoUnload(const bool autoUnload)
+{
+   // Ignore no change.
+   if (mpAssetDefinition->mAssetAutoUnload == autoUnload)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetAutoUnload = autoUnload;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetInternal(const bool assetInternal)
+{
+   // Ignore no change,
+   if (mpAssetDefinition->mAssetInternal == assetInternal)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetInternal = assetInternal;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetBase::expandAssetFilePath(const char* pAssetFilePath) const
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_ExpandAssetFilePath);
+
+   // Sanity!
+   AssertFatal(pAssetFilePath != NULL, "Cannot expand a NULL asset path.");
+
+   // Fetch asset file-path length.
+   const U32 assetFilePathLength = dStrlen(pAssetFilePath);
+
+   // Are there any characters in the path?
+   if (assetFilePathLength == 0)
+   {
+      // No, so return empty.
+      return StringTable->EmptyString();
+   }
+
+   // Fetch the asset base-path hint.
+   StringTableEntry assetBasePathHint;
+   if (getOwned() && !getAssetPrivate())
+   {
+      assetBasePathHint = mpOwningAssetManager->getAssetPath(getAssetId());
+   }
+   else
+   {
+      assetBasePathHint = NULL;
+   }
+
+   // Expand the path with the asset base-path hint.
+   char assetFilePathBuffer[1024];
+   Con::expandPath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath, assetBasePathHint);
+   return StringTable->insert(assetFilePathBuffer);
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetBase::collapseAssetFilePath(const char* pAssetFilePath) const
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_CollapseAssetFilePath);
+
+   // Sanity!
+   AssertFatal(pAssetFilePath != NULL, "Cannot collapse a NULL asset path.");
+
+   // Fetch asset file-path length.
+   const U32 assetFilePathLength = dStrlen(pAssetFilePath);
+
+   // Are there any characters in the path?
+   if (assetFilePathLength == 0)
+   {
+      // No, so return empty.
+      return StringTable->EmptyString();
+   }
+
+   char assetFilePathBuffer[1024];
+
+   // Is the asset not owned or private?
+   if (!getOwned() || getAssetPrivate())
+   {
+      // Yes, so we can only collapse the path using the platform layer.
+      Con::collapsePath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath);
+      return StringTable->insert(assetFilePathBuffer);
+   }
+
+   // Fetch asset base-path.
+   StringTableEntry assetBasePath = mpOwningAssetManager->getAssetPath(getAssetId());
+
+   // Is the asset file-path location within the asset base-path?
+   if (Con::isBasePath(pAssetFilePath, assetBasePath))
+   {
+      // Yes, so fetch path relative to the asset base-path.
+      StringTableEntry relativePath = Platform::makeRelativePathName(pAssetFilePath, assetBasePath);
+
+      // Format the collapsed path.
+      dSprintf(assetFilePathBuffer, sizeof(assetFilePathBuffer), "%s", relativePath);
+   }
+   else
+   {
+      // No, so we can collapse the path using the platform layer.
+      Con::collapsePath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath);
+   }
+
+   return StringTable->insert(assetFilePathBuffer);
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::refreshAsset(void)
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_RefreshAsset);
+
+   // Finish if asset is not owned or is not initialized.
+   if (mpOwningAssetManager == NULL || !mAssetInitialized)
+      return;
+
+   // Yes, so refresh the asset via the asset manager.
+   mpOwningAssetManager->refreshAsset(getAssetId());
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::acquireAssetReference(void)
+{
+   // Acquired the acquired reference count.
+   if (mpOwningAssetManager != NULL)
+      mpOwningAssetManager->acquireAcquiredReferenceCount();
+
+   mAcquireReferenceCount++;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetBase::releaseAssetReference(void)
+{
+   // Are there any acquisition references?
+   if (mAcquireReferenceCount == 0)
+   {
+      // Return "unload" unless auto unload is off.
+      return mpAssetDefinition->mAssetAutoUnload;
+   }
+
+   // Release the acquired reference count.
+   if (mpOwningAssetManager != NULL)
+      mpOwningAssetManager->releaseAcquiredReferenceCount();
+
+   // Release reference.
+   mAcquireReferenceCount--;
+
+   // Are there any acquisition references?
+   if (mAcquireReferenceCount == 0)
+   {
+      // No, so return "unload" unless auto unload is off.
+      return mpAssetDefinition->mAssetAutoUnload;
+   }
+
+   // Return "don't unload".
+   return false;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setOwned(AssetManager* pAssetManager, AssetDefinition* pAssetDefinition)
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_setOwned);
+
+   // Sanity!
+   AssertFatal(pAssetManager != NULL, "Cannot set asset ownership with NULL asset manager.");
+   AssertFatal(mpOwningAssetManager == NULL, "Cannot set asset ownership if it is already owned.");
+   AssertFatal(pAssetDefinition != NULL, "Cannot set asset ownership with a NULL asset definition.");
+   AssertFatal(mpAssetDefinition != NULL, "Asset ownership assigned but has a NULL asset definition.");
+   AssertFatal(mpAssetDefinition->mAssetName == pAssetDefinition->mAssetName, "Asset ownership differs by asset name.");
+   AssertFatal(mpAssetDefinition->mAssetDescription == pAssetDefinition->mAssetDescription, "Asset ownership differs by asset description.");
+   AssertFatal(mpAssetDefinition->mAssetCategory == pAssetDefinition->mAssetCategory, "Asset ownership differs by asset category.");
+   AssertFatal(mpAssetDefinition->mAssetAutoUnload == pAssetDefinition->mAssetAutoUnload, "Asset ownership differs by asset auto-unload flag.");
+   AssertFatal(mpAssetDefinition->mAssetInternal == pAssetDefinition->mAssetInternal, "Asset ownership differs by asset internal flag.");
+
+   // Transfer asset definition ownership state.
+   delete mpAssetDefinition;
+   mpAssetDefinition = pAssetDefinition;
+
+   // Flag as owned.
+   // NOTE: This must be done prior to initializing the asset so any initialization can assume ownership.
+   mpOwningAssetManager = pAssetManager;
+
+   // Initialize the asset.
+   initializeAsset();
+
+   // Flag asset as initialized.
+   mAssetInitialized = true;
+}

+ 145 - 0
Engine/source/assets/assetBase.h

@@ -0,0 +1,145 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#ifndef _ASSET_BASE_H_
+#define _ASSET_BASE_H_
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assetDefinition.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class AssetManager;
+
+//-----------------------------------------------------------------------------
+
+extern StringTableEntry assetNameField;
+extern StringTableEntry assetDescriptionField;
+extern StringTableEntry assetCategoryField;
+extern StringTableEntry assetInternalField;
+extern StringTableEntry assetPrivateField;
+extern StringTableEntry assetAutoUnloadField;
+
+//#define ASSET_BASE_ASSETNAME_FIELD         "AssetName"
+//#define ASSET_BASE_ASSETDESCRIPTION_FIELD  "AssetDescription"
+//#define ASSET_BASE_ASSETCATEGORY_FIELD     "AssetCategory"
+//#define ASSET_BASE_ASSETINTERNAL_FIELD     "AssetInternal"
+//#define ASSET_BASE_ASSETPRIVATE_FIELD      "AssetPrivate"
+//#define ASSET_BASE_AUTOUNLOAD_FIELD        "AssetAutoUnload"
+
+//-----------------------------------------------------------------------------
+
+class AssetBase : public SimObject
+{
+   friend class AssetManager;
+
+   typedef SimObject Parent;
+
+   AssetManager*           mpOwningAssetManager;
+   bool                    mAssetInitialized;
+   AssetDefinition*        mpAssetDefinition;
+   U32                     mAcquireReferenceCount;
+
+public:
+   AssetBase();
+   virtual ~AssetBase();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Asset configuration.
+   inline void             setAssetName(const char* pAssetName)              { if (mpOwningAssetManager == NULL) mpAssetDefinition->mAssetName = StringTable->insert(pAssetName); }
+   inline StringTableEntry getAssetName(void) const                          { return mpAssetDefinition->mAssetName; }
+   void                    setAssetDescription(const char* pAssetDescription);
+   inline StringTableEntry getAssetDescription(void) const                   { return mpAssetDefinition->mAssetDescription; }
+   void                    setAssetCategory(const char* pAssetCategory);
+   inline StringTableEntry getAssetCategory(void) const                      { return mpAssetDefinition->mAssetCategory; }
+   void                    setAssetAutoUnload(const bool autoUnload);
+   inline bool             getAssetAutoUnload(void) const                    { return mpAssetDefinition->mAssetAutoUnload; }
+   void                    setAssetInternal(const bool assetInternal);
+   inline bool             getAssetInternal(void) const                      { return mpAssetDefinition->mAssetInternal; }
+   inline bool             getAssetPrivate(void) const                       { return mpAssetDefinition->mAssetPrivate; }
+   inline StringTableEntry getAssetType(void) const                          { return mpAssetDefinition->mAssetType; }
+
+   inline S32              getAcquiredReferenceCount(void) const             { return mAcquireReferenceCount; }
+   inline bool             getOwned(void) const                              { return mpOwningAssetManager != NULL; }
+
+   // Asset Id is only available once registered with the asset manager.
+   inline StringTableEntry getAssetId(void) const                            { return mpAssetDefinition->mAssetId; }
+
+   /// Expanding/Collapsing asset paths is only available once registered with the asset manager.
+   StringTableEntry        expandAssetFilePath(const char* pAssetFilePath) const;
+   StringTableEntry        collapseAssetFilePath(const char* pAssetFilePath) const;
+
+   virtual bool            isAssetValid(void) const                          { return true; }
+
+   void                    refreshAsset(void);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(AssetBase);
+
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
+
+protected:
+   static bool             setAssetName(void *obj, const char *array, const char *data)           { static_cast<AssetBase*>(obj)->setAssetName(data); return false; }
+   static const char*      getAssetName(void* obj, const char* data)           { return static_cast<AssetBase*>(obj)->getAssetName(); }
+   static bool             writeAssetName(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetName() != StringTable->EmptyString(); }
+
+   static bool             setAssetDescription(void *obj, const char *array, const char *data)    { static_cast<AssetBase*>(obj)->setAssetDescription(data); return false; }
+   static const char*      getAssetDescription(void* obj, const char* data)    { return static_cast<AssetBase*>(obj)->getAssetDescription(); }
+   static bool             writeAssetDescription(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetDescription() != StringTable->EmptyString(); }
+
+   static bool             setAssetCategory(void *obj, const char *array, const char *data)       { static_cast<AssetBase*>(obj)->setAssetCategory(data); return false; }
+   static const char*      getAssetCategory(void* obj, const char* data)       { return static_cast<AssetBase*>(obj)->getAssetCategory(); }
+   static bool             writeAssetCategory(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetCategory() != StringTable->EmptyString(); }
+
+   static bool             setAssetAutoUnload(void *obj, const char *array, const char *data)     { static_cast<AssetBase*>(obj)->setAssetAutoUnload(dAtob(data)); return false; }
+   static const char*      getAssetAutoUnload(void* obj, const char* data)     { return Con::getBoolArg(static_cast<AssetBase*>(obj)->getAssetAutoUnload()); }
+   static bool             writeAssetAutoUnload(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetAutoUnload() == false; }
+
+   static bool             setAssetInternal(void *obj, const char *array, const char *data)       { static_cast<AssetBase*>(obj)->setAssetInternal(dAtob(data)); return false; }
+   static const char*      getAssetInternal(void* obj, const char* data)       { return Con::getBoolArg(static_cast<AssetBase*>(obj)->getAssetInternal()); }
+   static bool             writeAssetInternal(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetInternal() == true; }
+
+   static const char*      getAssetPrivate(void* obj, const char* data)        { return Con::getBoolArg(static_cast<AssetBase*>(obj)->getAssetPrivate()); }
+
+private:
+   void                    acquireAssetReference(void);
+   bool                    releaseAssetReference(void);
+
+   /// Set asset manager ownership.
+   void                    setOwned(AssetManager* pAssetManager, AssetDefinition* pAssetDefinition);
+};
+
+#endif // _ASSET_BASE_H_
+

+ 41 - 0
Engine/source/assets/assetBase_ScriptBinding.h

@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#include "console/engineAPI.h"
+#include "assetBase.h"
+#include "assetManager.h"
+
+
+DefineEngineMethod(AssetBase, refreshAsset, void, (), ,
+   "Refresh the asset.\n"
+   "@return No return value.\n")
+{
+    object->refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetBase, getAssetId, String, (), ,
+   "Gets the assets' Asset Id.  This is only available if the asset was acquired from the asset manager.\n"
+   "@return The assets' Asset Id.\n")
+{
+    return object->getAssetId();
+}

+ 102 - 0
Engine/source/assets/assetDefinition.h

@@ -0,0 +1,102 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_DEFINITION_H_
+#define _ASSET_DEFINITION_H_
+
+#ifndef _STRINGTABLE_H_
+#include "core/stringTable.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "core/strings/stringUnit.h"
+#endif
+
+#ifndef _SIM_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _SIMOBJECT_H_
+#include "console/simObject.h"
+#endif
+
+#ifndef _CONSOLEOBJECT_H_
+#include "console/consoleObject.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class AssetBase;
+class ModuleDefinition;
+
+//-----------------------------------------------------------------------------
+
+struct AssetDefinition
+{
+public:
+    AssetDefinition() { reset(); }
+    virtual ~AssetDefinition() {}
+
+    virtual void reset( void )
+    {
+        mAssetLoading = false;
+        mpModuleDefinition = NULL;
+        mpAssetBase = NULL;
+        mAssetBaseFilePath = StringTable->EmptyString();
+        mAssetId = StringTable->EmptyString();
+        mAssetLoadedCount = 0;
+        mAssetUnloadedCount = 0;
+        mAssetRefreshEnable = true;
+        mAssetLooseFiles.clear();
+
+        // Reset persisted state.
+        mAssetName = StringTable->EmptyString();
+        mAssetDescription = StringTable->EmptyString();
+        mAssetAutoUnload = true;
+        mAssetInternal = false;
+        mAssetPrivate = false;
+        mAssetType = StringTable->EmptyString();
+        mAssetCategory = StringTable->EmptyString();
+    }
+
+    ModuleDefinition*           mpModuleDefinition;
+    AssetBase*                  mpAssetBase;
+    StringTableEntry            mAssetBaseFilePath;
+    StringTableEntry            mAssetId;
+    U32                         mAssetLoadedCount;
+    U32                         mAssetUnloadedCount;
+    bool                        mAssetRefreshEnable;
+    Vector<StringTableEntry>    mAssetLooseFiles;
+
+    /// Persisted state.
+    StringTableEntry            mAssetName;
+    StringTableEntry            mAssetDescription;
+    bool                        mAssetAutoUnload;
+    bool                        mAssetInternal; 
+    bool                        mAssetPrivate;
+    bool                        mAssetLoading;
+    StringTableEntry            mAssetType;
+    StringTableEntry            mAssetCategory;
+};
+
+#endif // _ASSET_DEFINITION_H_
+

+ 114 - 0
Engine/source/assets/assetFieldTypes.cpp

@@ -0,0 +1,114 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assetFieldTypes.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assetPtr.h"
+#endif
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+/*#ifndef _AUDIO_ASSET_H_
+#include "audio/AudioAsset.h"
+#endif*/
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry assetLooseIdSignature = StringTable->insert( ASSET_ID_SIGNATURE );
+StringTableEntry assetLooseFileSignature = StringTable->insert( ASSET_LOOSEFILE_SIGNATURE );
+
+//-----------------------------------------------------------------------------
+
+ConsoleType( assetLooseFilePath, TypeAssetLooseFilePath, String, ASSET_LOOSE_FILE_FIELD_PREFIX )
+ConsoleType(assetIdString, TypeAssetId, String, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType( TypeAssetLooseFilePath )
+{
+    // Fetch asset loose file-path.
+    return *((StringTableEntry*)dptr);
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType( TypeAssetLooseFilePath )
+{
+    // Was a single argument specified?
+    if( argc == 1 )
+    {
+        // Yes, so fetch field value.
+        const char* pFieldValue = argv[0];
+
+        // Fetch asset loose file-path.
+        StringTableEntry* assetLooseFilePath = (StringTableEntry*)(dptr);
+
+        // Update asset loose file-path value.
+        *assetLooseFilePath = StringTable->insert(pFieldValue);
+
+        return;
+    }
+
+    // Warn.
+    Con::warnf( "(TypeAssetLooseFilePath) - Cannot set multiple args to a single asset loose-file." );
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType( TypeAssetId )
+{
+    // Fetch asset Id.
+    return *((StringTableEntry*)dptr);
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType( TypeAssetId )
+{
+    // Was a single argument specified?
+    if( argc == 1 )
+    {
+        // Yes, so fetch field value.
+        const char* pFieldValue = argv[0];
+
+        // Fetch asset Id.
+        StringTableEntry* assetId = (StringTableEntry*)(dptr);
+
+        // Update asset value.
+        *assetId = StringTable->insert(pFieldValue);
+
+        return;
+    }
+
+    // Warn.
+    Con::warnf( "(TypeAssetId) - Cannot set multiple args to a single asset." );
+}
+

+ 56 - 0
Engine/source/assets/assetFieldTypes.h

@@ -0,0 +1,56 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#define _ASSET_FIELD_TYPES_H_
+
+#ifndef _CONSOLE_BASE_TYPE_H_
+#include "console/consoleTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleType( TypeAssetId, S32 )
+DefineConsoleType( TypeAssetLooseFilePath, String )
+
+//-----------------------------------------------------------------------------
+
+/// Asset scope.
+#define ASSET_SCOPE_TOKEN				":"
+
+/// Asset assignment.
+#define ASSET_ASSIGNMENT_TOKEN			"="
+
+/// Asset Id.
+#define ASSET_ID_SIGNATURE              "@asset"
+#define ASSET_ID_FIELD_PREFIX           "@asset="
+
+/// Asset loose file.
+#define ASSET_LOOSEFILE_SIGNATURE       "@assetFile"
+#define ASSET_LOOSE_FILE_FIELD_PREFIX   "@assetFile="
+
+//-----------------------------------------------------------------------------
+
+extern StringTableEntry assetLooseIdSignature;
+extern StringTableEntry assetLooseFileSignature;
+
+#endif // _ASSET_FIELD_TYPES_H_

+ 3017 - 0
Engine/source/assets/assetManager.cpp

@@ -0,0 +1,3017 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "assetManager.h"
+
+#ifndef _ASSET_PTR_H_
+#include "assetPtr.h"
+#endif
+
+#ifndef _REFERENCED_ASSETS_H_
+#include "assets/referencedAssets.h"
+#endif
+
+#ifndef _DECLARED_ASSETS_H_
+#include "assets/declaredAssets.h"
+#endif
+
+#ifndef _TAML_ASSET_REFERENCED_VISITOR_H_
+#include "tamlAssetReferencedVisitor.h"
+#endif
+
+#ifndef _TAML_ASSET_DECLARED_VISITOR_H_
+#include "tamlAssetDeclaredVisitor.h"
+#endif
+
+#ifndef _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_
+#include "tamlAssetDeclaredUpdateVisitor.h"
+#endif
+
+#ifndef _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_
+#include "tamlAssetReferencedUpdateVisitor.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+// Script bindings.
+#include "assetManager_ScriptBinding.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( AssetManager );
+
+//-----------------------------------------------------------------------------
+
+AssetManager AssetDatabase;
+
+//-----------------------------------------------------------------------------
+
+AssetManager::AssetManager() :
+    mLoadedInternalAssetsCount( 0 ),
+    mLoadedExternalAssetsCount( 0 ),
+    mLoadedPrivateAssetsCount( 0 ),
+    mMaxLoadedInternalAssetsCount( 0 ),
+    mMaxLoadedExternalAssetsCount( 0 ),
+    mMaxLoadedPrivateAssetsCount( 0 ),
+    mAcquiredReferenceCount( 0 ),
+    mEchoInfo( false ),
+    mIgnoreAutoUnload( false )
+{
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::onAdd()
+{
+    // Call parent.
+    if ( !Parent::onAdd() )
+        return false;
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onRemove()
+{
+    // Do we have an asset tags manifest?
+    if ( !mAssetTagsManifest.isNull() )
+    {
+        // Yes, so remove it.
+        mAssetTagsManifest->deleteObject();
+    }
+
+    // Call parent.
+    Parent::onRemove();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::initPersistFields()
+{
+    // Call parent.
+    Parent::initPersistFields();
+
+    addField( "EchoInfo", TypeBool, Offset(mEchoInfo, AssetManager), "Whether the asset manager echos extra information to the console or not." );
+    addField( "IgnoreAutoUnload", TypeBool, Offset(mIgnoreAutoUnload, AssetManager), "Whether the asset manager should ignore unloading of auto-unload assets or not." );
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::compileReferencedAssets( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_CompileReferencedAsset);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot add declared assets using a NULL module definition" );
+
+    // Clear referenced assets.
+    mReferencedAssets.clear();
+
+    // Iterate the module definition children.
+    for( SimSet::iterator itr = pModuleDefinition->begin(); itr != pModuleDefinition->end(); ++itr )
+    {
+        // Fetch the referenced assets.
+        ReferencedAssets* pReferencedAssets = dynamic_cast<ReferencedAssets*>( *itr );
+
+        // Skip if it's not a referenced assets location.
+        if ( pReferencedAssets == NULL )
+            continue;
+
+        // Expand asset manifest location.
+        char filePathBuffer[1024];
+        dSprintf( filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pReferencedAssets->getPath() );
+
+        // Scan referenced assets at location.
+        if ( !scanReferencedAssets( filePathBuffer, pReferencedAssets->getExtension(), pReferencedAssets->getRecurse() ) )
+        {
+            // Warn.
+            Con::warnf( "AssetManager::compileReferencedAssets() - Could not scan for referenced assets at location '%s' with extension '%s'.", filePathBuffer, pReferencedAssets->getExtension() );
+        }
+    }  
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::addModuleDeclaredAssets( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddDeclaredAssets);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot add declared assets using a NULL module definition" );
+
+    // Does the module have any assets associated with it?
+    if ( pModuleDefinition->getModuleAssets().size() > 0 )
+    {
+        // Yes, so warn.
+        Con::warnf( "Asset Manager: Cannot add declared assets to module '%s' as it already has existing assets.", pModuleDefinition->getSignature() );
+        return false;
+    }
+
+    // Iterate the module definition children.
+    for( SimSet::iterator itr = pModuleDefinition->begin(); itr != pModuleDefinition->end(); ++itr )
+    {
+        // Fetch the declared assets.
+        DeclaredAssets* pDeclaredAssets = dynamic_cast<DeclaredAssets*>( *itr );
+
+        // Skip if it's not a declared assets location.
+        if ( pDeclaredAssets == NULL )
+            continue;
+
+        // Expand asset manifest location.
+        char filePathBuffer[1024];
+        String mdldfpth = pModuleDefinition->getModulePath();
+        String astfpth = pDeclaredAssets->getPath();
+
+        //dSprintf( filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pDeclaredAssets->getPath() );
+        dSprintf(filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pDeclaredAssets->getPath());
+
+        // Scan declared assets at location.
+        if ( !scanDeclaredAssets( filePathBuffer, pDeclaredAssets->getExtension(), pDeclaredAssets->getRecurse(), pModuleDefinition ) )
+        {
+            // Warn.
+            Con::warnf( "AssetManager::addModuleDeclaredAssets() - Could not scan for declared assets at location '%s' with extension '%s'.", filePathBuffer, pDeclaredAssets->getExtension() );
+        }
+    }  
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::addDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddSingleDeclaredAsset);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot add single declared asset using a NULL module definition" );
+    AssertFatal( pAssetFilePath != NULL, "Cannot add single declared asset using a NULL asset file-path." );
+
+    // Expand asset file-path.
+    char assetFilePathBuffer[1024];
+    Con::expandPath( assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath );
+
+    // Find the final slash which should be just before the file.
+    char* pFileStart = dStrrchr( assetFilePathBuffer, '/' );
+
+    // Did we find the final slash?
+    if ( pFileStart == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "AssetManager::addDeclaredAsset() - Could not add single declared asset file '%s' as file-path '%s' is not valid.",
+            assetFilePathBuffer,
+            pModuleDefinition->getModulePath() );
+        return false;
+    }
+
+    // Terminate path at slash.
+    *pFileStart = 0;
+
+    // Move to next character which should be the file start.
+    pFileStart++;
+
+    // Scan declared assets at location.
+    if ( !scanDeclaredAssets( assetFilePathBuffer, pFileStart, false, pModuleDefinition ) )
+    {
+        // Warn.
+        Con::warnf( "AssetManager::addDeclaredAsset() - Could not scan declared assets at location '%s' with extension '%s'.", assetFilePathBuffer, pFileStart );
+        return false;
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::addPrivateAsset( AssetBase* pAssetBase )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddPrivateAsset);
+
+    // Sanity!
+    AssertFatal( pAssetBase != NULL, "Cannot add a NULL private asset." );
+
+    // Is the asset already added?
+    if (pAssetBase->mpAssetDefinition->mAssetId != StringTable->EmptyString())
+    {
+        // Yes, so warn.
+        Con::warnf( "Cannot add private asset '%d' as it has already been assigned.", pAssetBase->mpAssetDefinition->mAssetId );
+        return StringTable->EmptyString();
+    }
+
+    static U32 masterPrivateAssetId = 1;
+
+    // Create asset definition.
+    AssetDefinition* pAssetDefinition = new AssetDefinition();
+
+    // Fetch source asset definition.
+    AssetDefinition* pSourceAssetDefinition = pAssetBase->mpAssetDefinition;
+
+    // Configure asset.
+    pAssetDefinition->mpAssetBase = pAssetBase;
+    pAssetDefinition->mAssetDescription = pSourceAssetDefinition->mAssetDescription;
+    pAssetDefinition->mAssetCategory = pSourceAssetDefinition->mAssetCategory;
+    pAssetDefinition->mAssetAutoUnload = true;
+    pAssetDefinition->mAssetRefreshEnable = false;
+    pAssetDefinition->mAssetType = StringTable->insert( pAssetBase->getClassName() );
+    pAssetDefinition->mAssetLoadedCount = 0;
+    pAssetDefinition->mAssetInternal = false;
+    pAssetDefinition->mAssetPrivate = true;
+
+    // Format asset name.
+    char assetNameBuffer[256];
+    dSprintf(assetNameBuffer, sizeof(assetNameBuffer), "%s_%d", pAssetDefinition->mAssetType, masterPrivateAssetId++ );    
+
+    // Set asset identity.
+    pAssetDefinition->mAssetName = StringTable->insert( assetNameBuffer );
+    pAssetDefinition->mAssetId = pAssetDefinition->mAssetName;
+
+    // Ensure that the source asset is fully synchronized with the new asset definition.
+    pSourceAssetDefinition->mAssetName = pAssetDefinition->mAssetName;
+    pSourceAssetDefinition->mAssetAutoUnload = pAssetDefinition->mAssetAutoUnload;
+    pSourceAssetDefinition->mAssetInternal = pAssetDefinition->mAssetInternal;
+
+    // Set ownership by asset manager.
+    pAssetDefinition->mpAssetBase->setOwned( this, pAssetDefinition );
+
+    // Store in declared assets.
+    mDeclaredAssets.insert( pAssetDefinition->mAssetId, pAssetDefinition );
+
+    // Increase the private loaded asset count.
+    if ( ++mLoadedPrivateAssetsCount > mMaxLoadedPrivateAssetsCount )
+        mMaxLoadedPrivateAssetsCount = mLoadedPrivateAssetsCount;
+
+    return pAssetDefinition->mAssetId;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::removeDeclaredAssets( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemoveDeclaredAssets);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot remove declared assets using a NULL module definition" );
+
+    // Fetch module assets.
+    ModuleDefinition::typeModuleAssetsVector& moduleAssets = pModuleDefinition->getModuleAssets();
+
+    // Remove all module assets.
+    while ( moduleAssets.size() > 0 )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = *moduleAssets.begin();
+
+        // Remove this asset.
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
+    }
+
+    // Info.
+    if ( mEchoInfo )
+        Con::printSeparator();
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::removeDeclaredAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemoveSingleDeclaredAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot remove single declared asset using NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Find declared asset.
+    typeDeclaredAssetsHash::iterator declaredAssetItr = mDeclaredAssets.find( assetId );
+
+    // Did we find the declared asset?
+    if ( declaredAssetItr == mDeclaredAssets.end() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot remove single asset Id '%s' it could not be found.", assetId );
+        return false;
+    }
+
+    // Fetch asset definition.
+    AssetDefinition* pAssetDefinition = declaredAssetItr->value;
+
+    // Is the asset private?
+    if ( !pAssetDefinition->mAssetPrivate )
+    {
+        // No, so fetch module assets.
+        ModuleDefinition::typeModuleAssetsVector& moduleAssets = pAssetDefinition->mpModuleDefinition->getModuleAssets();
+
+        // Remove module asset.
+        for ( ModuleDefinition::typeModuleAssetsVector::iterator moduleAssetItr = moduleAssets.begin(); moduleAssetItr != moduleAssets.end(); ++moduleAssetItr )
+        {
+            if ( *moduleAssetItr == pAssetDefinition )
+            {
+                moduleAssets.erase( moduleAssetItr );
+                break;
+            }
+        }
+
+        // Remove asset dependencies.
+        removeAssetDependencies( pAssetId );
+    }
+
+    // Do we have an asset loaded?
+    if ( pAssetDefinition->mpAssetBase != NULL )
+    {
+        // Yes, so delete it.
+        // NOTE: If anything is using this then this'll cause a crash.  Objects should always use safe reference methods however.
+        pAssetDefinition->mpAssetBase->deleteObject();
+    }
+
+    // Remove from declared assets.
+    mDeclaredAssets.erase( declaredAssetItr );
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: Removing Asset Id '%s' of type '%s' in asset file '%s'.",
+            pAssetDefinition->mAssetId,
+            pAssetDefinition->mAssetType,
+            pAssetDefinition->mAssetBaseFilePath );
+    }
+
+    // Destroy asset definition.
+    delete pAssetDefinition;
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetName( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetName;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetDescription( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetDescription;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetCategory( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetCategory;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetType( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetType;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetFilePath( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return StringTable->EmptyString();
+    }
+
+    return pAssetDefinition->mAssetBaseFilePath;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetPath( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_GetAssetPath);
+
+    // Fetch asset file-path.
+    StringTableEntry assetFilePath = getAssetFilePath( pAssetId );
+
+    // Finish if no file-path.
+    if ( assetFilePath == StringTable->EmptyString()  )
+        return assetFilePath;
+
+    // Find the final slash which should be just before the file.
+    const char* pFinalSlash = dStrrchr( assetFilePath, '/' );
+
+    // Sanity!
+    AssertFatal( pFinalSlash != NULL, "Should always be able to find final slash in the asset file-path." );
+
+    // Fetch asset path.
+    return StringTable->insertn( assetFilePath, (U32)(pFinalSlash - assetFilePath) );
+}
+
+//-----------------------------------------------------------------------------
+
+ModuleDefinition* AssetManager::getAssetModuleDefinition( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mpModuleDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetInternal( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mAssetInternal;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetPrivate( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mAssetPrivate;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetAutoUnload( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mAssetAutoUnload;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetLoaded( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mpAssetBase != NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isDeclaredAsset( const char* pAssetId )
+{
+    return findAsset( pAssetId ) != NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::doesAssetDependOn( const char* pAssetId, const char* pDependsOnAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_DoesAssetDependOn);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+    AssertFatal( pDependsOnAssetId != NULL, "Cannot use NULL depends-on asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Fetch depends-on asset Id.
+    StringTableEntry dependsOnAssetId = StringTable->insert( pDependsOnAssetId );
+
+    // Find depends-on entry.
+    typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find( assetId );
+
+    // Iterate all dependencies.
+    while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == assetId )
+    {
+        // Finish if a depends on.
+        if ( dependsOnItr->value == dependsOnAssetId )
+            return true;
+
+        // Next dependency.
+        dependsOnItr++;
+    }
+
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetDependedOn( const char* pAssetId, const char* pDependedOnByAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_IsAssetDependedOn);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+    AssertFatal( pDependedOnByAssetId != NULL, "Cannot use NULL depended-on-by asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Fetch depended-on-by asset Id.
+    StringTableEntry dependedOnByAssetId = StringTable->insert( pDependedOnByAssetId );
+
+    // Find depended-on-by entry.
+    typeAssetDependsOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find(assetId);
+
+    // Iterate all dependencies.
+    while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
+    {
+        // Finish if depended-on.
+        if ( dependedOnItr->value == dependedOnByAssetId )
+            return true;
+
+        // Next dependency.
+        dependedOnItr++;
+    }
+
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isReferencedAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_IsReferencedAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot check if NULL asset Id is referenced." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Is asset Id the correct format?
+    if ( StringUnit::getUnitCount( assetId, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot check if asset Id '%s' is referenced as it is not the correct format.", assetId );
+        return false;
+    }
+
+    return mReferencedAssets.count( assetId ) > 0;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameDeclaredAsset);
+
+    // Sanity!
+    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
+    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
+
+    // Fetch asset Ids.
+    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
+    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
+
+    // Is asset Id from the correct format?
+    if ( StringUnit::getUnitCount( assetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as source asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Is asset Id to the correct format?
+    if ( StringUnit::getUnitCount( assetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as target asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Does the asset Id from exist?
+    if ( !mDeclaredAssets.contains( assetIdFrom ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as source asset Id is not declared.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Does the asset Id to exist?
+    if ( mDeclaredAssets.contains( assetIdTo ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as target asset Id is already declared.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Split module Ids from asset Ids.
+    StringTableEntry moduleIdFrom = StringTable->insert( StringUnit::getUnit( assetIdFrom, 0, ASSET_SCOPE_TOKEN ) );
+    StringTableEntry moduleIdTo   = StringTable->insert( StringUnit::getUnit( assetIdTo, 0, ASSET_SCOPE_TOKEN ) );
+
+    // Are the module Ids the same?
+    if ( moduleIdFrom != moduleIdTo )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the module Id cannot be changed.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Find asset definition.
+    typeDeclaredAssetsHash::iterator assetDefinitionItr =  mDeclaredAssets.find( assetIdFrom );
+
+    // Sanity!
+    AssertFatal( assetDefinitionItr != mDeclaredAssets.end(), "Asset Manager: Failed to find asset." );
+
+    // Fetch asset definition.
+    AssetDefinition* pAssetDefinition = assetDefinitionItr->value;
+
+    // Is this a private asset?
+    if ( pAssetDefinition->mAssetPrivate )
+    {
+        // Yes, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the source asset is private.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Setup declared update visitor.
+    TamlAssetDeclaredUpdateVisitor assetDeclaredUpdateVisitor;
+    assetDeclaredUpdateVisitor.setAssetIdFrom( assetIdFrom );
+    assetDeclaredUpdateVisitor.setAssetIdTo( assetIdTo );
+
+    // Update asset file declaration.
+    if ( !mTaml.parse( pAssetDefinition->mAssetBaseFilePath, assetDeclaredUpdateVisitor ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the declared asset file could not be parsed: %s",
+            assetIdFrom, assetIdTo, pAssetDefinition->mAssetBaseFilePath );
+        return false;
+    }
+
+    // Update asset definition.
+    pAssetDefinition->mAssetId = assetIdTo;
+    pAssetDefinition->mAssetName = StringTable->insert( StringUnit::getUnit( assetIdTo, 1, ASSET_SCOPE_TOKEN ) );
+
+    // Reinsert declared asset.
+    mDeclaredAssets.erase( assetIdFrom );
+    mDeclaredAssets.insert( assetIdTo, pAssetDefinition );
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: Renaming declared Asset Id '%s' to Asset Id '%s'.", assetIdFrom, assetIdTo );
+        Con::printSeparator();
+    }
+
+    // Rename asset dependencies.
+    renameAssetDependencies( assetIdFrom, assetIdTo );
+
+    // Do we have an asset tags manifest?
+    if ( !mAssetTagsManifest.isNull() )
+    {
+        // Yes, so rename any assets.
+        mAssetTagsManifest->renameAssetId( pAssetIdFrom, pAssetIdTo );
+
+        // Save the asset tags.
+        saveAssetTags();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameReferencedAsset);
+
+    // Sanity!
+    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
+    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
+
+    // Fetch asset Ids.
+    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
+    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
+
+    // Is asset Id from the correct format?
+    if ( StringUnit::getUnitCount( assetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as source asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Is asset Id to the correct format?
+    if ( StringUnit::getUnitCount( assetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as target asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Does the asset Id to exist?
+    if ( !mDeclaredAssets.contains( assetIdTo ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as target asset Id is not declared.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Rename asset references.
+    renameAssetReferences( assetIdFrom, assetIdTo );
+
+    // Info.
+    if ( mEchoInfo )
+        Con::printSeparator();
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::releaseAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_ReleaseAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot release NULL asset Id." );
+
+    // Find asset.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to release asset Id '%s' as it does not exist.", pAssetId );
+        return false;
+    }
+
+    // Is the asset loaded?
+    if ( pAssetDefinition->mpAssetBase == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to release asset Id '%s' as it is not acquired.", pAssetId );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started releasing Asset Id '%s'...", pAssetId );
+    }
+
+    // Release asset reference.
+    if ( pAssetDefinition->mpAssetBase->releaseAssetReference() )
+    {
+        // Are we ignoring auto-unloaded assets?
+        if ( mIgnoreAutoUnload )
+        {
+            // Yes, so info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Releasing to idle state." );
+            }
+        }
+        else
+        {
+            // No, so info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Unload the asset from memory." );
+            }
+
+            // Unload the asset.
+            unloadAsset( pAssetDefinition );
+        }
+    }
+    // Info.
+    else if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: > Reference count now '%d'.", pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() );
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: > Finished releasing Asset Id '%s'.", pAssetId );
+        Con::printSeparator();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::purgeAssets( void )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_PurgeAssets);
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: Started purging assets..." );
+    }
+
+    // Iterate asset definitions.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = assetItr->value;
+
+        // Skip asset if private, not loaded or referenced.
+        if (    pAssetDefinition->mAssetPrivate ||
+                pAssetDefinition->mpAssetBase == NULL ||
+                pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() > 0 )
+            continue;
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: Purging asset Id '%s'...", pAssetDefinition->mAssetId );
+        }
+
+        // Unload the asset.
+        unloadAsset( pAssetDefinition );
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: ... Finished purging assets." );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_DeleteAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot delete NULL asset Id." );
+
+    // Find asset.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to delete asset Id '%s' as it does not exist.", pAssetId );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started deleting Asset Id '%s'...", pAssetId );
+    }  
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Are we deleting dependencies?
+    if ( deleteDependencies )
+    {
+        Vector<typeAssetId> dependantAssets;
+
+        // Yes, so find depended-on-by entry.
+        typeAssetDependsOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find( assetId );
+
+        // Iterate all dependencies.
+        while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
+        {
+            // Store asset Id.
+            dependantAssets.push_back( dependedOnItr->value );
+
+            // Next dependency.
+            dependedOnItr++;
+        }
+
+        // Do we have any dependants?
+        if ( dependantAssets.size() > 0 )
+        {
+            // Yes, so iterate dependants.
+            for( Vector<typeAssetId>::const_iterator assetItr = dependantAssets.begin(); assetItr !=  dependantAssets.end(); ++assetItr )
+            {
+                StringTableEntry dependentAssetId = *assetItr;
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printSeparator();
+                    Con::printf( "Asset Manager: Deleting Asset Id '%s' dependant of '%s.'", pAssetId, dependentAssetId );
+                }
+
+                // Delete dependant.
+                deleteAsset( dependentAssetId, deleteLooseFiles, deleteDependencies );
+            }
+        }
+    }
+
+    // Remove asset references.
+    removeAssetReferences( assetId );
+
+    // Are we deleting loose files?
+    if ( deleteLooseFiles )
+    {
+        // Yes, so remove loose files.
+        Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
+        for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
+        {
+            // Fetch loose file.
+            StringTableEntry looseFile = *looseFileItr;
+
+            // Delete the loose file.
+            if ( !dFileDelete( looseFile ) )
+            {
+                // Failed so warn.
+                Con::warnf( "Asset Manager: Failed to delete the loose file '%s' while deleting asset Id '%s'.", looseFile, pAssetId );
+            }
+        }
+    }
+
+    // Fetch asset definition file.
+    StringTableEntry assetDefinitionFile = pAssetDefinition->mAssetBaseFilePath;
+
+    // Remove reference here as we're about to remove the declared asset.
+    pAssetDefinition = NULL;
+
+    // Remove asset.
+    removeDeclaredAsset( pAssetId );
+
+    // Delete the asset definition file.
+    if ( !dFileDelete( assetDefinitionFile ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to delete the asset definition file '%s' while deleting asset Id '%s'.", assetDefinitionFile, pAssetId );
+    }       
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Finished deleting Asset Id '%s'.", pAssetId );
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::refreshAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RefreshAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot refresh NULL asset Id." );
+
+    // Find asset.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to refresh asset Id '%s' as it does not exist.", pAssetId );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started refreshing Asset Id '%s'...", pAssetId );
+    }    
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Is the asset private?
+    if ( pAssetDefinition->mAssetPrivate )
+    {
+        // Yes, so notify asset of asset refresh only.
+        pAssetDefinition->mpAssetBase->onAssetRefresh();
+
+        // Asset refresh notifications.
+        for( typeAssetPtrRefreshHash::iterator refreshNotifyItr = mAssetPtrRefreshNotifications.begin(); refreshNotifyItr != mAssetPtrRefreshNotifications.end(); ++refreshNotifyItr )
+        {
+            // Fetch pointed asset.
+            StringTableEntry pointedAsset = refreshNotifyItr->key->getAssetId();
+
+            // Ignore if the pointed asset is not the asset or a dependency.
+            if ( pointedAsset == StringTable->EmptyString() || ( pointedAsset != assetId && !doesAssetDependOn( pointedAsset, assetId ) ) )
+                continue;
+
+            // Perform refresh notification callback.
+            refreshNotifyItr->value->onAssetRefreshed( refreshNotifyItr->key );
+        }
+    }
+    // Is the asset definition allowed to refresh?
+    else if ( pAssetDefinition->mAssetRefreshEnable )
+    {
+        // Yes, so fetch the asset.
+        AssetBase* pAssetBase = pAssetDefinition->mpAssetBase;
+
+        // Is the asset loaded?
+        if ( pAssetBase != NULL )
+        {
+            // Yes, so notify asset of asset refresh.
+            pAssetBase->onAssetRefresh();
+
+            // Save asset.
+            mTaml.write( pAssetBase, pAssetDefinition->mAssetBaseFilePath );
+        
+            // Remove asset dependencies.
+            removeAssetDependencies( pAssetId );
+
+            // Find any new dependencies.
+            TamlAssetDeclaredVisitor assetDeclaredVisitor;
+
+            // Parse the filename.
+            if ( !mTaml.parse( pAssetDefinition->mAssetBaseFilePath, assetDeclaredVisitor ) )
+            {
+                // Warn.
+                Con::warnf( "Asset Manager: Failed to parse file containing asset declaration: '%s'.\nDependencies are now incorrect!", pAssetDefinition->mAssetBaseFilePath );
+                return false;
+            }
+
+            // Fetch asset dependencies.
+            TamlAssetDeclaredVisitor::typeAssetIdVector& assetDependencies = assetDeclaredVisitor.getAssetDependencies();
+
+            // Are there any asset dependences?
+            if ( assetDependencies.size() > 0 )
+            {
+                // Yes, so iterate dependencies.
+                for( TamlAssetDeclaredVisitor::typeAssetIdVector::iterator assetDependencyItr = assetDependencies.begin(); assetDependencyItr != assetDependencies.end(); ++assetDependencyItr )
+                {
+                    // Fetch dependency asset Id.
+                    StringTableEntry dependencyAssetId = *assetDependencyItr;
+
+                    // Insert depends-on.
+                    mAssetDependsOn.insertEqual( assetId, dependencyAssetId );
+
+                    // Insert is-depended-on.
+                    mAssetIsDependedOn.insertEqual( dependencyAssetId, assetId );
+                }
+            }
+
+            // Fetch asset loose files.
+            TamlAssetDeclaredVisitor::typeLooseFileVector& assetLooseFiles = assetDeclaredVisitor.getAssetLooseFiles();
+
+            // Clear any existing loose files.
+            pAssetDefinition->mAssetLooseFiles.clear();
+
+            // Are there any loose files?
+            if ( assetLooseFiles.size() > 0 )
+            {
+                // Yes, so iterate loose files.
+                for( TamlAssetDeclaredVisitor::typeLooseFileVector::iterator assetLooseFileItr = assetLooseFiles.begin(); assetLooseFileItr != assetLooseFiles.end(); ++assetLooseFileItr )
+                {
+                    // Store loose file.
+                    pAssetDefinition->mAssetLooseFiles.push_back( *assetLooseFileItr );
+                }
+            }
+
+            // Asset refresh notifications.
+            for( typeAssetPtrRefreshHash::iterator refreshNotifyItr = mAssetPtrRefreshNotifications.begin(); refreshNotifyItr != mAssetPtrRefreshNotifications.end(); ++refreshNotifyItr )
+            {
+                // Fetch pointed asset.
+                StringTableEntry pointedAsset = refreshNotifyItr->key->getAssetId();
+
+                // Ignore if the pointed asset is not the asset or a dependency.
+                if ( pointedAsset == StringTable->EmptyString() || ( pointedAsset != assetId && !doesAssetDependOn( pointedAsset, assetId ) ) )
+                    continue;
+
+                // Perform refresh notification callback.
+                refreshNotifyItr->value->onAssetRefreshed( refreshNotifyItr->key );
+            }
+
+            // Find is-depends-on entry.
+            typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find( assetId );
+
+            // Is asset depended on?
+            if ( isDependedOnItr != mAssetIsDependedOn.end() )
+            {
+                // Yes, so compiled them.
+                Vector<typeAssetId> dependedOn;
+
+                // Iterate all dependencies.
+                while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == assetId )
+                {
+                    dependedOn.push_back( isDependedOnItr->value );
+
+                    // Next dependency.
+                    isDependedOnItr++;
+                }
+
+                // Refresh depended-on assets.
+                for ( Vector<typeAssetId>::iterator isDependedOnItr = dependedOn.begin(); isDependedOnItr != dependedOn.end(); ++isDependedOnItr )
+                {
+                    // Refresh dependency asset.
+                    refreshAsset( *isDependedOnItr );
+                }
+            }
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Finished refreshing Asset Id '%s'.", pAssetId );
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::refreshAllAssets( const bool includeUnloaded )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RefreshAllAssets);
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started refreshing ALL assets." );
+    }
+
+    Vector<typeAssetId> assetsToRelease;
+
+    // Are we including unloaded assets?
+    if ( includeUnloaded )
+    {
+        // Yes, so prepare a list of assets to release and load them.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset Id.
+            typeAssetId assetId = assetItr->key;
+
+            // Skip if asset is loaded.
+            if ( assetItr->value->mpAssetBase != NULL )
+                continue;
+
+            // Note asset as needing a release.
+            assetsToRelease.push_back( assetId );
+
+            // Acquire the asset.
+            acquireAsset<AssetBase>( assetId );
+        }
+    }
+
+    // Refresh the current loaded assets.
+    // NOTE: This will result in some assets being refreshed more than once due to asset dependencies.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Skip private assets.
+        if ( assetItr->value->mAssetPrivate )
+            continue;
+
+        // Refresh asset if it's loaded.
+        refreshAsset( assetItr->key );
+    }
+
+    // Are we including unloaded assets?
+    if ( includeUnloaded )
+    {
+        // Yes, so release the assets we loaded.
+        for( Vector<typeAssetId>::iterator assetItr = assetsToRelease.begin(); assetItr != assetsToRelease.end(); ++assetItr )
+        {
+            releaseAsset( *assetItr );
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Finished refreshing ALL assets." );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::registerAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase, AssetPtrCallback* pCallback )
+{
+    // Find an existing notification iterator.
+    typeAssetPtrRefreshHash::iterator notificationItr = mAssetPtrRefreshNotifications.find( pAssetPtrBase );
+
+    // Do we have one?
+    if ( notificationItr != mAssetPtrRefreshNotifications.end() )
+    {
+        // Yes, so update the callback.
+        notificationItr->value = pCallback;
+        return;
+    }
+
+    // No, so add one.
+    mAssetPtrRefreshNotifications.insert( pAssetPtrBase, pCallback );
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::unregisterAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase )
+{
+    mAssetPtrRefreshNotifications.erase( pAssetPtrBase );
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::loadAssetTags( ModuleDefinition* pModuleDefinition )
+{
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot load asset tags manifest using a NULL module definition" );
+
+    // Expand manifest location.
+    char assetTagsManifestFilePathBuffer[1024];
+    Con::expandPath( assetTagsManifestFilePathBuffer, sizeof(assetTagsManifestFilePathBuffer), pModuleDefinition->getAssetTagsManifest() );
+
+    // Do we already have a manifest?
+    if ( !mAssetTagsManifest.isNull() )
+    {
+        // Yes, so warn.
+        Con::warnf( "Asset Manager: Cannot load asset tags manifest from module '%s' as one is already loaded.", pModuleDefinition->getSignature() );
+        return false;
+    }
+
+    // Is the specified file valid?
+    if ( Platform::isFile( assetTagsManifestFilePathBuffer ) )
+    {
+        // Yes, so read asset tags manifest.
+        mAssetTagsManifest = mTaml.read<AssetTagsManifest>( assetTagsManifestFilePathBuffer );
+
+        // Did we read the manifest?
+        if ( mAssetTagsManifest.isNull() )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: Failed to load asset tags manifest '%s' from module '%s'.", assetTagsManifestFilePathBuffer, pModuleDefinition->getSignature() );
+            return false;
+        }
+
+        // Set asset tags module definition.
+        mAssetTagsModuleDefinition = pModuleDefinition;
+    }
+    else
+    {
+        // No, so generate a new asset tags manifest.
+        mAssetTagsManifest = new AssetTagsManifest();
+        mAssetTagsManifest->registerObject();
+
+        // Set asset tags module definition.
+        mAssetTagsModuleDefinition = pModuleDefinition;
+
+        // Save the asset tags.
+        saveAssetTags();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::saveAssetTags( void )
+{
+    // Do we have an asset tags manifest?
+    if ( mAssetTagsManifest.isNull() || mAssetTagsModuleDefinition.isNull() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to save asset tags manifest as one is not loaded." );
+        return false;
+    }
+
+    // Expand manifest location.
+    char assetTagsManifestFilePathBuffer[1024];
+    Con::expandPath( assetTagsManifestFilePathBuffer, sizeof(assetTagsManifestFilePathBuffer), mAssetTagsModuleDefinition->getAssetTagsManifest() );
+
+    // Save asset tags manifest.
+    if ( !mTaml.write( mAssetTagsManifest, assetTagsManifestFilePathBuffer ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to save asset tags manifest '%s' from module '%s'.", assetTagsManifestFilePathBuffer, mAssetTagsModuleDefinition->getSignature() );
+        return false;
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::restoreAssetTags( void )
+{
+    // Do we already have a manifest?
+    if ( mAssetTagsManifest.isNull() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot restore asset tags manifest as one is not already loaded." );
+        return false;
+    }
+
+    // Sanity!
+    AssertFatal( mAssetTagsModuleDefinition != NULL, "Cannot restore asset tags manifest as module definition is NULL." );
+
+    // Delete existing asset tags manifest.
+    mAssetTagsManifest->deleteObject();
+
+    // Reload asset tags manifest.
+    return loadAssetTags( mAssetTagsModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+S32 QSORT_CALLBACK descendingAssetDefinitionLoadCount(const void* a, const void* b)
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_DescendingAssetDefinitionLoadCount);
+
+    // Fetch asset definitions.
+    const AssetDefinition* pAssetDefinitionA  = *(AssetDefinition**)a;
+    const AssetDefinition* pAssetDefinitionB  = *(AssetDefinition**)b;
+
+    // Sort.
+    return pAssetDefinitionB->mAssetLoadedCount - pAssetDefinitionA->mAssetLoadedCount;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::dumpDeclaredAssets( void ) const
+{
+    Vector<const AssetDefinition*> assetDefinitions;
+
+    // Iterate asset definitions.
+    for( typeDeclaredAssetsHash::const_iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        assetDefinitions.push_back( assetItr->value );
+    }
+
+    // Sort asset definitions.
+    dQsort( assetDefinitions.address(), assetDefinitions.size(), sizeof(const AssetDefinition*), descendingAssetDefinitionLoadCount );
+
+    // Info.
+    Con::printSeparator();
+    Con::printf( "Asset Manager: %d declared asset(s) dump as follows:", mDeclaredAssets.size() );
+    Con::printBlankLine();
+
+    // Iterate sorted asset definitions.
+    for ( Vector<const AssetDefinition*>::iterator assetItr = assetDefinitions.begin(); assetItr != assetDefinitions.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        const AssetDefinition* pAssetDefinition = *assetItr;
+
+        // Info.
+        Con::printf( "AssetId:'%s', RefCount:%d, LoadCount:%d, UnloadCount:%d, AutoUnload:%d, Loaded:%d, Internal:%d, Private: %d, Type:'%s', Module/Version:'%s'/'%d', File:'%s'",
+            pAssetDefinition->mAssetId,
+            pAssetDefinition->mpAssetBase == NULL ? 0 : pAssetDefinition->mpAssetBase->getAcquiredReferenceCount(),
+            pAssetDefinition->mAssetLoadedCount,
+            pAssetDefinition->mAssetUnloadedCount,
+            pAssetDefinition->mAssetAutoUnload,
+            pAssetDefinition->mpAssetBase != NULL,
+            pAssetDefinition->mAssetInternal,
+            pAssetDefinition->mAssetPrivate,
+            pAssetDefinition->mAssetType,
+            pAssetDefinition->mpModuleDefinition->getModuleId(),
+            pAssetDefinition->mpModuleDefinition->getVersionId(),
+            pAssetDefinition->mAssetBaseFilePath );
+    }
+
+    // Info.
+    Con::printSeparator();
+    Con::printBlankLine();
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAllAssets( AssetQuery* pAssetQuery, const bool ignoreInternal, const bool ignorePrivate )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAllAssets);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Iterate declared assets.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = assetItr->value;
+
+        // Skip if internal and we're ignoring them.
+        if ( ignoreInternal && pAssetDefinition->mAssetInternal )
+            continue;
+
+        // Skip if private and we're ignoring them.
+        if ( ignorePrivate && pAssetDefinition->mAssetPrivate )
+            continue;
+
+        // Store as result.
+        pAssetQuery->mAssetList.push_back( pAssetDefinition->mAssetId );
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetName( AssetQuery* pAssetQuery, const char* pAssetName, const bool partialName )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetName);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetName != NULL, "Cannot use NULL asset name." );
+
+    // Reset asset name.
+    StringTableEntry assetName = NULL;
+    S32 partialAssetNameLength = 0;
+        
+    // Are we doing partial name search?
+    if ( partialName ) 
+    {
+        // Yes, so fetch length of partial name.
+        partialAssetNameLength = dStrlen( pAssetName );
+    }
+    else
+    {
+        // No, so fetch asset name.
+        assetName = StringTable->insert( pAssetName );
+    }
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Iterate declared assets.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = assetItr->value;
+
+        // Are we doing partial name search?
+        if ( partialName ) 
+        {
+            // Yes, so fetch the length of this asset name.
+            const S32 currentAssetNameLength = dStrlen( pAssetDefinition->mAssetName );
+
+            // Skip if the query asset name is longer than the current asset name.
+            if ( partialAssetNameLength > currentAssetNameLength )
+                continue;
+            
+            // Skip if this is not the asset we want.
+            if ( dStrnicmp( pAssetDefinition->mAssetName, pAssetName, partialAssetNameLength ) != 0 )
+                continue;
+        }
+        else
+        {
+            // No, so skip if this is not the asset we want.
+            if ( assetName != pAssetDefinition->mAssetName )
+                continue;
+        }
+
+        // Store as result.
+        pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+    
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetCategory( AssetQuery* pAssetQuery, const char* pAssetCategory, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetCategory);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetCategory != NULL, "Cannot use NULL asset category." );
+
+    // Fetch asset category.
+    StringTableEntry assetCategory = StringTable->insert( pAssetCategory );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetCategory != assetCategory )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetCategory != pAssetDefinition->mAssetCategory )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+S32 AssetManager::findAssetAutoUnload( AssetQuery* pAssetQuery, const bool assetAutoUnload, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetAutoUnload);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetAutoUnload != assetAutoUnload )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetAutoUnload != pAssetDefinition->mAssetAutoUnload )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetInternal( AssetQuery* pAssetQuery, const bool assetInternal, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetInternal);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetInternal != assetInternal )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetInternal != pAssetDefinition->mAssetInternal )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetPrivate( AssetQuery* pAssetQuery, const bool assetPrivate, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetPrivate);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetPrivate != assetPrivate )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetPrivate != pAssetDefinition->mAssetPrivate )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetType( AssetQuery* pAssetQuery, const char* pAssetType, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetType);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetType != NULL, "Cannot use NULL asset type." );
+
+    // Fetch asset type.
+    StringTableEntry assetType = StringTable->insert( pAssetType );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetType != assetType )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetType != pAssetDefinition->mAssetType )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetDependsOn( AssetQuery* pAssetQuery, const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetDependsOn);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Find depends-on entry.
+    typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find( assetId );
+
+    // Iterate all dependencies.
+    while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == assetId )
+    {
+        // Store as result.
+       pAssetQuery->mAssetList.push_back(dependsOnItr->value);
+
+        // Next dependency.
+        dependsOnItr++;
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetIsDependedOn( AssetQuery* pAssetQuery, const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetIsDependedOn);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Find depended-on entry.
+    typeAssetIsDependedOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find( assetId );
+
+    // Iterate all dependencies.
+    while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
+    {
+        // Store as result.
+       pAssetQuery->mAssetList.push_back(dependedOnItr->value);
+
+        // Next dependency.
+        dependedOnItr++;
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findInvalidAssetReferences( AssetQuery* pAssetQuery )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindInvalidAssetReferences);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Iterate referenced assets.
+    for( typeReferencedAssetsHash::Iterator assetItr = mReferencedAssets.begin(); assetItr != mReferencedAssets.end(); ++assetItr )
+    {
+        // Find asset definition.
+        AssetDefinition* pAssetDefinition = findAsset( assetItr->key );
+
+        // Skip if the asset definition was found.
+        if ( pAssetDefinition != NULL )
+            continue;
+
+        // Store as result.
+        pAssetQuery->mAssetList.push_back(assetItr->key);
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findTaggedAssets( AssetQuery* pAssetQuery, const char* pAssetTagNames, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindTaggedAssets);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetTagNames != NULL, "Cannot use NULL asset tag name(s)." );
+
+    // Do we have an asset tag manifest?
+    if ( mAssetTagsManifest.isNull() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find tagged assets as no asset tag manifest is present." );
+        return 0;
+    }
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    const char* pTagSeparators = " ,\t\n";
+
+    // Fetch tag count.
+    U32 assetTagCount = StringUnit::getUnitCount( pAssetTagNames, pTagSeparators );
+
+    // Fetch asset tags.
+    Vector<AssetTagsManifest::AssetTag*> assetTags;
+    for( U32 tagIndex = 0; tagIndex < assetTagCount; ++tagIndex )
+    {
+        // Fetch asset tag name.
+        const char* pTagName = StringUnit::getUnit( pAssetTagNames, tagIndex, pTagSeparators );
+
+        // Fetch asset tag.
+        AssetTagsManifest::AssetTag* pAssetTag = mAssetTagsManifest->findAssetTag( pTagName );
+
+        // Did we find the asset tag?
+        if ( pAssetTag == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest: Asset Manager: Cannot find tagged assets of '%s' as it does not exist.  Ignoring tag.", pTagName );
+            continue;
+        }
+
+        assetTags.push_back( pAssetTag );
+    }
+
+    // Fetch found asset tag count.
+    assetTagCount = assetTags.size();
+
+    // Did we find any tags?
+    if ( assetTagCount == 0 )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest: Asset Manager: No specified tagged assets found in '%s'.", pAssetTagNames );
+        return 0;
+    } 
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset Id.
+            StringTableEntry assetId = *assetItr;
+
+            // Skip if asset is not valid.
+            if ( !isDeclaredAsset( assetId ) )
+                continue;
+
+            // Reset matched flag.
+            bool assetTagMatched = false;
+
+            // Iterate asset tags.
+            for ( Vector<AssetTagsManifest::AssetTag*>::iterator assetTagItr = assetTags.begin(); assetTagItr != assetTags.end(); ++assetTagItr )
+            {
+                // Fetch asset tag.
+                AssetTagsManifest::AssetTag* pAssetTag = *assetTagItr;
+
+                // Skip if asset is not tagged.
+                if ( !pAssetTag->containsAsset( assetId ) )
+                    continue;
+                
+                // Flag as matched.
+                assetTagMatched = true;
+                break;
+            }
+
+            // Did we find a match?
+            if ( assetTagMatched )
+            {
+                // Yes, so is asset already present?
+                if ( !filteredAssets.containsAsset( assetId ) )
+                {
+                    // No, so store as result.
+                   filteredAssets.mAssetList.push_back(assetId);
+
+                    // Increase result count.
+                    resultCount++;
+                }
+            }
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // Iterate asset tags.
+        for ( Vector<AssetTagsManifest::AssetTag*>::iterator assetTagItr = assetTags.begin(); assetTagItr != assetTags.end(); ++assetTagItr )
+        {
+            // Fetch asset tag.
+            AssetTagsManifest::AssetTag* pAssetTag = *assetTagItr;
+
+            // Iterate tagged assets.
+            for ( Vector<typeAssetId>::iterator assetItr = pAssetTag->mAssets.begin(); assetItr != pAssetTag->mAssets.end(); ++assetItr )
+            {
+                // Fetch asset Id.
+                StringTableEntry assetId = *assetItr;
+
+                // Skip if asset Id is already present.
+                if ( pAssetQuery->containsAsset( assetId ) )
+                    continue;
+
+                // Store as result.
+                pAssetQuery->mAssetList.push_back(assetId);
+
+                // Increase result count.
+                resultCount++;
+            }
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetLooseFile( AssetQuery* pAssetQuery, const char* pLooseFile, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetLooseFile);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pLooseFile != NULL, "Cannot use NULL loose file." );
+
+    // Expand loose file.
+    char looseFileBuffer[1024];
+    Con::expandPath(looseFileBuffer, sizeof(looseFileBuffer), pLooseFile, NULL, false );
+
+    // Fetch asset loose file.
+    StringTableEntry looseFile = StringTable->insert( looseFileBuffer );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Fetch loose files.
+            Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
+
+            // Skip if this asset has no loose files.
+            if ( assetLooseFiles.size() == 0 )
+                continue;
+
+            // Search the assets loose files.
+            for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
+            {
+                // Is this the loose file we are searching for?
+                if ( *looseFileItr != looseFile )
+                    continue;
+
+                // Store as result.
+                filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+                // Increase result count.
+                resultCount++;
+
+                break;
+            }
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Fetch loose files.
+            Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
+
+            // Skip if this asset has no loose files.
+            if ( assetLooseFiles.size() == 0 )
+                continue;
+
+            // Search the assets loose files.
+            for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
+            {
+                // Is this the loose file we are searching for?
+                if ( *looseFileItr != looseFile )
+                    continue;
+
+                // Store as result.
+                pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+                // Increase result count.
+                resultCount++;
+
+                break;
+            }
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::scanDeclaredAssets( const char* pPath, const char* pExtension, const bool recurse, ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_ScanDeclaredAssets);
+
+    // Sanity!
+    AssertFatal( pPath != NULL, "Cannot scan declared assets with NULL path." );
+    AssertFatal( pExtension != NULL, "Cannot scan declared assets with NULL extension." );
+
+    // Expand path location.
+    char pathBuffer[1024];
+    Con::expandPath( pathBuffer, sizeof(pathBuffer), pPath );
+
+    // Find files.
+    Vector<Platform::FileInfo> files;
+    if ( !Platform::dumpPath( pathBuffer, files, recurse ? -1 : 0 ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to scan declared assets in directory '%s'.", pathBuffer );
+        return false;
+    }
+
+    // Is the asset file-path located within the specified module?
+    if ( !Con::isBasePath( pathBuffer, pModuleDefinition->getModulePath() ) )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Could not add declared asset file '%s' as file does not exist with module path '%s'",
+            pathBuffer,
+            pModuleDefinition->getModulePath() );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Scanning for declared assets in path '%s' for files with extension '%s'...", pathBuffer, pExtension );
+    }
+
+    // Fetch extension length.
+    const U32 extensionLength = dStrlen( pExtension );
+
+    // Fetch module assets.
+    ModuleDefinition::typeModuleAssetsVector& moduleAssets = pModuleDefinition->getModuleAssets();
+
+    TamlAssetDeclaredVisitor assetDeclaredVisitor;
+
+    // Iterate files.
+    for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr )
+    {
+        // Fetch file info.
+        Platform::FileInfo& fileInfo = *fileItr;
+
+        // Fetch filename.
+        const char* pFilename = fileInfo.pFileName;
+
+        // Find filename length.
+        const U32 filenameLength = dStrlen( pFilename );
+
+        // Skip if extension is longer than filename.
+        if ( extensionLength > filenameLength )
+            continue;
+
+        // Skip if extension not found.
+        if ( dStricmp( pFilename + filenameLength - extensionLength, pExtension ) != 0 )
+            continue;
+
+        // Clear declared assets.
+        assetDeclaredVisitor.clear();
+
+        // Format full file-path.
+        char assetFileBuffer[1024];
+        dSprintf( assetFileBuffer, sizeof(assetFileBuffer), "%s/%s", fileInfo.pFullPath, fileInfo.pFileName );
+
+        // Parse the filename.
+        if ( !mTaml.parse( assetFileBuffer, assetDeclaredVisitor ) )
+        {
+            // Warn.
+            Con::warnf( "Asset Manager: Failed to parse file containing asset declaration: '%s'.", assetFileBuffer );
+            continue;
+        }
+
+        // Fetch asset definition.
+        AssetDefinition& foundAssetDefinition = assetDeclaredVisitor.getAssetDefinition();
+
+        // Did we get an asset name?
+        if ( foundAssetDefinition.mAssetName == StringTable->EmptyString() )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: Parsed file '%s' but did not encounter an asset.", assetFileBuffer );
+            continue;
+        }
+
+        // Set module definition.
+        foundAssetDefinition.mpModuleDefinition = pModuleDefinition;
+
+        // Format asset Id.
+        char assetIdBuffer[1024];
+        dSprintf(assetIdBuffer, sizeof(assetIdBuffer), "%s%s%s",
+            pModuleDefinition->getModuleId(),
+            ASSET_SCOPE_TOKEN,
+            foundAssetDefinition.mAssetName );
+
+        // Set asset Id.
+        foundAssetDefinition.mAssetId = StringTable->insert( assetIdBuffer );
+
+        // Does this asset already exist?
+        if ( mDeclaredAssets.contains( foundAssetDefinition.mAssetId ) )
+        {
+            // Yes, so warn.
+            Con::warnf( "Asset Manager: Encountered asset Id '%s' in asset file '%s' but it conflicts with existing asset Id in asset file '%s'.",
+                foundAssetDefinition.mAssetId,
+                foundAssetDefinition.mAssetBaseFilePath,
+                mDeclaredAssets.find( foundAssetDefinition.mAssetId )->value->mAssetBaseFilePath );
+
+            continue;
+        }
+
+        // Create new asset definition.
+        AssetDefinition* pAssetDefinition = new AssetDefinition( foundAssetDefinition );
+
+        // Store in declared assets.
+        mDeclaredAssets.insert( pAssetDefinition->mAssetId, pAssetDefinition );
+
+        // Store in module assets.
+        moduleAssets.push_back( pAssetDefinition );
+        
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printSeparator();
+            Con::printf( "Asset Manager: Adding Asset Id '%s' of type '%s' in asset file '%s'.",
+                pAssetDefinition->mAssetId,
+                pAssetDefinition->mAssetType,
+                pAssetDefinition->mAssetBaseFilePath );
+        }
+
+        // Fetch asset Id.
+        StringTableEntry assetId = pAssetDefinition->mAssetId;
+
+        // Fetch asset dependencies.
+        TamlAssetDeclaredVisitor::typeAssetIdVector& assetDependencies = assetDeclaredVisitor.getAssetDependencies();
+
+        // Are there any asset dependencies?
+        if ( assetDependencies.size() > 0 )
+        {
+            // Yes, so iterate dependencies.
+            for( TamlAssetDeclaredVisitor::typeAssetIdVector::iterator assetDependencyItr = assetDependencies.begin(); assetDependencyItr != assetDependencies.end(); ++assetDependencyItr )
+            {
+                // Fetch asset Ids.
+                StringTableEntry dependencyAssetId = *assetDependencyItr;
+
+                // Insert depends-on.
+                mAssetDependsOn.insertEqual( assetId, dependencyAssetId );
+
+                // Insert is-depended-on.
+                mAssetIsDependedOn.insertEqual( dependencyAssetId, assetId );
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printf( "Asset Manager: Asset Id '%s' has dependency of Asset Id '%s'", assetId, dependencyAssetId );
+                }
+            }
+        }
+
+        // Fetch asset loose files.
+        TamlAssetDeclaredVisitor::typeLooseFileVector& assetLooseFiles = assetDeclaredVisitor.getAssetLooseFiles();
+
+        // Are there any loose files?
+        if ( assetLooseFiles.size() > 0 )
+        {
+            // Yes, so iterate loose files.
+            for( TamlAssetDeclaredVisitor::typeLooseFileVector::iterator assetLooseFileItr = assetLooseFiles.begin(); assetLooseFileItr != assetLooseFiles.end(); ++assetLooseFileItr )
+            {
+                // Fetch loose file.
+                StringTableEntry looseFile = *assetLooseFileItr;
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printf( "Asset Manager: Asset Id '%s' has loose file '%s'.", assetId, looseFile );
+                }
+
+                // Store loose file.
+                pAssetDefinition->mAssetLooseFiles.push_back( looseFile );
+            }
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: ... Finished scanning for declared assets in path '%s' for files with extension '%s'.", pathBuffer, pExtension );
+        Con::printSeparator();
+        Con::printBlankLine();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::scanReferencedAssets( const char* pPath, const char* pExtension, const bool recurse )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_ScanReferencedAssets);
+
+    // Sanity!
+    AssertFatal( pPath != NULL, "Cannot scan referenced assets with NULL path." );
+    AssertFatal( pExtension != NULL, "Cannot scan referenced assets with NULL extension." );
+
+    // Expand path location.
+    char pathBuffer[1024];
+    Con::expandPath( pathBuffer, sizeof(pathBuffer), pPath );
+
+    // Find files.
+    Vector<Platform::FileInfo> files;
+    if ( !Platform::dumpPath( pathBuffer, files, recurse ? -1 : 0 ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to scan referenced assets in directory '%s'.", pathBuffer );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Scanning for referenced assets in path '%s' for files with extension '%s'...", pathBuffer, pExtension );
+    }
+
+    // Fetch extension length.
+    const U32 extensionLength = dStrlen( pExtension );
+
+    TamlAssetReferencedVisitor assetReferencedVisitor;
+
+    // Iterate files.
+    for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr )
+    {
+        // Fetch file info.
+        Platform::FileInfo& fileInfo = *fileItr;
+
+        // Fetch filename.
+        const char* pFilename = fileInfo.pFileName;
+
+        // Find filename length.
+        const U32 filenameLength = dStrlen( pFilename );
+
+        // Skip if extension is longer than filename.
+        if ( extensionLength > filenameLength )
+            continue;
+
+        // Skip if extension not found.
+        if ( dStricmp( pFilename + filenameLength - extensionLength, pExtension ) != 0 )
+            continue;
+
+        // Clear referenced assets.
+        assetReferencedVisitor.clear();
+
+        // Format full file-path.
+        char assetFileBuffer[1024];
+        dSprintf( assetFileBuffer, sizeof(assetFileBuffer), "%s/%s", fileInfo.pFullPath, fileInfo.pFileName );
+
+        // Format reference file-path.
+        typeReferenceFilePath referenceFilePath = StringTable->insert( assetFileBuffer );
+
+        // Parse the filename.
+        if ( !mTaml.parse( referenceFilePath, assetReferencedVisitor ) )
+        {
+            // Warn.
+            Con::warnf( "Asset Manager: Failed to parse file containing asset references: '%s'.", referenceFilePath );
+            continue;
+        }
+
+        // Fetch usage map.
+        const TamlAssetReferencedVisitor::typeAssetReferencedHash& assetReferencedMap = assetReferencedVisitor.getAssetReferencedMap();
+
+        // Do we have any asset references?
+        if ( assetReferencedMap.size() > 0 )
+        {
+            // Info.
+            if ( mEchoInfo )
+            {
+                Con::printSeparator();
+            }
+
+            // Iterate usage.
+            for( TamlAssetReferencedVisitor::typeAssetReferencedHash::const_iterator usageItr = assetReferencedMap.begin(); usageItr != assetReferencedMap.end(); ++usageItr )
+            {
+                // Fetch asset name.
+                typeAssetId assetId = usageItr->key;
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printf( "Asset Manager: Found referenced Asset Id '%s' in file '%s'.", assetId, referenceFilePath );
+                }
+
+                // Add referenced asset.
+                addReferencedAsset( assetId, referenceFilePath );
+            }
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: ... Finished scanning for referenced assets in path '%s' for files with extension '%s'.", pathBuffer, pExtension );
+        Con::printSeparator();
+        Con::printBlankLine();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+AssetDefinition* AssetManager::findAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot find NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Find declared asset.
+    typeDeclaredAssetsHash::iterator declaredAssetItr = mDeclaredAssets.find( assetId );
+
+    // Find if we didn't find a declared asset Id.
+    if ( declaredAssetItr == mDeclaredAssets.end() )
+        return NULL;
+
+    return declaredAssetItr->value;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::addReferencedAsset( StringTableEntry assetId, StringTableEntry referenceFilePath )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddReferencedAsset);
+
+    // Sanity!
+    AssertFatal( assetId != NULL, "Cannot add referenced asset with NULL asset Id." );
+    AssertFatal( referenceFilePath != NULL, "Cannot add referenced asset with NULL reference file-path." );
+
+    // Find referenced asset.
+    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find( assetId );
+
+    // Did we find the asset?
+    if ( referencedAssetItr == mReferencedAssets.end() )
+    {
+        // No, so add asset Id.
+        mReferencedAssets.insertEqual( assetId, referenceFilePath );
+    }
+    else
+    {
+        // Yes, so add asset Id with a unique file.
+        while( true )
+        {
+            // Finish if this file is already present.
+            if ( referencedAssetItr->value == referenceFilePath )
+                return;
+
+            // Move to next asset Id.
+            referencedAssetItr++;
+
+            // Is this the end of referenced assets or a different asset Id?
+            if ( referencedAssetItr == mReferencedAssets.end() ||
+                referencedAssetItr->key != assetId )
+            {
+                // Yes, so add asset reference.
+                mReferencedAssets.insertEqual( assetId, referenceFilePath );
+                return;
+            }
+        };
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::renameAssetReferences( StringTableEntry assetIdFrom, StringTableEntry assetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameAssetReferences);
+
+    // Sanity!
+    AssertFatal( assetIdFrom != NULL, "Cannot rename asset references using NULL asset Id from." );
+    AssertFatal( assetIdTo != NULL, "Cannot rename asset references using NULL asset Id to." );
+
+    // Finish if the asset is not referenced.
+    if ( !mReferencedAssets.count( assetIdFrom ) )
+        return;
+
+    // Setup referenced update visitor.
+    TamlAssetReferencedUpdateVisitor assetReferencedUpdateVisitor;
+    assetReferencedUpdateVisitor.setAssetIdFrom( assetIdFrom );
+    assetReferencedUpdateVisitor.setAssetIdTo( assetIdTo );
+
+    // Find first referenced asset Id.
+    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find( assetIdFrom );
+
+    // Iterate references.
+    while( true )
+    {
+        // Finish if end of references.
+        if ( referencedAssetItr == mReferencedAssets.end() || referencedAssetItr->key != assetIdFrom )
+            return;
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: Renaming declared Asset Id '%s' to Asset Id '%s'.  Updating referenced file '%s'",
+                assetIdFrom,
+                assetIdTo,
+                referencedAssetItr->value );
+        }
+
+        // Update asset file declaration.
+        if ( !mTaml.parse( referencedAssetItr->value, assetReferencedUpdateVisitor ) )
+        {
+            // No, so warn.
+            Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as the referenced asset file could not be parsed: %s",
+                assetIdFrom, assetIdTo, referencedAssetItr->value );
+        }
+
+        // Move to next reference.
+        referencedAssetItr++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::removeAssetReferences( StringTableEntry assetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemoveAssetReferences);
+
+    // Sanity!
+    AssertFatal( assetId != NULL, "Cannot rename asset references using NULL asset Id." );
+
+    // Finish if the asset is not referenced.
+    if ( !mReferencedAssets.count( assetId ) )
+        return;
+
+    // Setup referenced update visitor.
+    TamlAssetReferencedUpdateVisitor assetReferencedUpdateVisitor;
+    assetReferencedUpdateVisitor.setAssetIdFrom( assetId );
+    assetReferencedUpdateVisitor.setAssetIdTo( StringTable->EmptyString() );
+
+    // Find first referenced asset Id.
+    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find(assetId);
+
+    // Iterate references.
+    while( true )
+    {
+        // Finish if end of references.
+        if ( referencedAssetItr == mReferencedAssets.end() || referencedAssetItr->key != assetId )
+            break;
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: Removing Asset Id '%s' references from file '%s'",
+                assetId,
+                referencedAssetItr->value );
+        }
+
+        // Update asset file declaration.
+        if ( !mTaml.parse( referencedAssetItr->value, assetReferencedUpdateVisitor ) )
+        {
+            // No, so warn.
+            Con::warnf("Asset Manager: Cannot remove referenced asset Id '%s' as the referenced asset file could not be parsed: %s",
+                assetId,
+                referencedAssetItr->value );
+        }
+
+        // Move to next reference.
+        referencedAssetItr++;
+    }
+
+    // Remove asset references.
+    mReferencedAssets.erase( assetId );
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::renameAssetDependencies( StringTableEntry assetIdFrom, StringTableEntry assetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameAssetDependencies);
+
+    // Sanity!
+    AssertFatal( assetIdFrom != NULL, "Cannot rename asset dependencies using NULL asset Id from." );
+    AssertFatal( assetIdTo != NULL, "Cannot rename asset dependencies using NULL asset Id to." );
+
+    // Rename via depends-on...
+    while( mAssetDependsOn.count( assetIdFrom ) > 0 )
+    {
+        // Find depends-on.
+       typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(assetIdFrom);
+
+        // Fetch dependency asset Id.
+        StringTableEntry dependencyAssetId = dependsOnItr->value;
+
+        // Find is-depends-on entry.
+        typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find(dependencyAssetId);
+
+        // Sanity!
+        AssertFatal( isDependedOnItr != mAssetIsDependedOn.end(), "Asset dependencies are corrupt!" );
+
+        while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value != assetIdFrom )
+        {
+            isDependedOnItr++;
+        }
+
+        // Sanity!
+        AssertFatal( isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value == assetIdFrom, "Asset dependencies are corrupt!" );
+        
+        // Remove is-depended-on.        
+        mAssetIsDependedOn.erase( isDependedOnItr );
+
+        // Remove depends-on.
+        mAssetDependsOn.erase( dependsOnItr );
+
+        // Insert depends-on.
+        mAssetDependsOn.insertEqual( assetIdTo, dependencyAssetId );
+
+        // Insert is-depended-on.
+        mAssetIsDependedOn.insertEqual( dependencyAssetId, assetIdTo );
+    }
+
+    // Rename via is-depended-on...
+    while( mAssetIsDependedOn.count( assetIdFrom ) > 0 )
+    {
+        // Find is-depended-on.
+       typeAssetIsDependedOnHash::Iterator isdependedOnItr = mAssetIsDependedOn.find(assetIdFrom);
+
+        // Fetch dependency asset Id.
+        StringTableEntry dependencyAssetId = isdependedOnItr->value;
+
+        // Find depends-on entry.
+        typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(dependencyAssetId);
+
+        // Sanity!
+        AssertFatal( dependsOnItr != mAssetDependsOn.end(), "Asset dependencies are corrupt!" );
+
+        while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == dependencyAssetId && dependsOnItr->value != assetIdFrom )
+        {
+            dependsOnItr++;
+        }
+
+        // Sanity!
+        AssertFatal( dependsOnItr->key == dependencyAssetId && dependsOnItr->value == assetIdFrom, "Asset dependencies are corrupt!" );
+        
+        // Remove is-depended-on.        
+        mAssetIsDependedOn.erase( isdependedOnItr );
+
+        // Remove depends-on.
+        mAssetDependsOn.erase( dependsOnItr );
+
+        // Insert depends-on.
+        mAssetDependsOn.insertEqual( dependencyAssetId, assetIdTo );
+
+        // Insert is-depended-on.
+        mAssetIsDependedOn.insertEqual( assetIdTo, dependencyAssetId );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::removeAssetDependencies( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemvoeAsetDependencies);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot remove asset dependencies using NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Remove from depends-on assets.
+    while( mAssetDependsOn.count( assetId ) > 0 )
+    {
+        // Find depends-on.
+       typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(assetId);
+
+        // Fetch dependency asset Id.
+        StringTableEntry dependencyAssetId = dependsOnItr->value;
+
+        // Find is-depends-on entry.
+        typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find(dependencyAssetId);
+
+        // Sanity!
+        AssertFatal( isDependedOnItr != mAssetIsDependedOn.end(), "Asset dependencies are corrupt!" );
+
+        while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value != assetId )
+        {
+            isDependedOnItr++;
+        }
+
+        // Sanity!
+        AssertFatal( isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value == assetId, "Asset dependencies are corrupt!" );
+
+        // Remove is-depended-on.        
+        mAssetIsDependedOn.erase( isDependedOnItr );
+
+        // Remove depends-on.
+        mAssetDependsOn.erase( dependsOnItr );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::unloadAsset( AssetDefinition* pAssetDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_UnloadAsset);
+
+    // Destroy the asset.
+    pAssetDefinition->mpAssetBase->deleteObject();
+
+    // Increase unloaded count.
+    pAssetDefinition->mAssetUnloadedCount++;
+
+    // Is the asset internal?
+    if ( pAssetDefinition->mAssetInternal )
+    {
+        // Yes, so decrease internal loaded asset count.
+        mLoadedInternalAssetsCount--;
+    }
+    else
+    {
+        // No, so decrease external loaded assets count.
+        mLoadedExternalAssetsCount--;
+    }
+
+    // Is the asset private?
+    if ( pAssetDefinition->mAssetPrivate )
+    {
+        // Yes, so decrease private loaded asset count.
+        mLoadedPrivateAssetsCount--;
+
+        // Remove it completely.
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onModulePreLoad( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_OnModulePreLoad);
+
+    // Add module declared assets.
+    addModuleDeclaredAssets( pModuleDefinition );
+
+    // Is an asset tags manifest specified?
+    if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString() )
+    {
+        // Yes, so load the asset tags manifest.
+        loadAssetTags( pModuleDefinition );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onModulePreUnload( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_OnModulePreUnload);
+
+    // Is an asset tags manifest specified?
+    if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString() )
+    {
+        // Yes, so save the asset tags manifest.
+        saveAssetTags();
+
+        // Do we have an asset tags manifest?
+        if ( !mAssetTagsManifest.isNull() )
+        {
+            // Yes, so remove it.
+            mAssetTagsManifest->deleteObject();
+            mAssetTagsModuleDefinition = NULL;
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onModulePostUnload( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_OnModulePostUnload);
+
+    // Remove declared assets.
+    removeDeclaredAssets( pModuleDefinition );
+}

+ 395 - 0
Engine/source/assets/assetManager.h

@@ -0,0 +1,395 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_MANAGER_H_
+#define _ASSET_MANAGER_H_
+
+#ifndef _SIMBASE_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _TAML_H_
+#include "persistence/taml/taml.h"
+#endif
+
+#ifndef _MODULE_DEFINITION_H
+#include "module/moduleDefinition.h"
+#endif
+
+#ifndef _MODULE_CALLBACKS_H_
+#include "module/moduleCallbacks.h"
+#endif
+
+#ifndef _ASSET_BASE_H_
+#include "assets/assetBase.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assets/assetDefinition.h"
+#endif
+
+#ifndef _ASSET_TAGS_MANIFEST_H_
+#include "assets/assetTagsManifest.h"
+#endif
+
+#ifndef _ASSET_QUERY_H_
+#include "assets/assetQuery.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class AssetPtrCallback;
+class AssetPtrBase;
+
+//-----------------------------------------------------------------------------
+
+class AssetManager : public SimObject, public ModuleCallbacks
+{
+private:
+    typedef SimObject Parent;
+    typedef StringTableEntry typeAssetId;
+    typedef StringTableEntry typeAssetName;
+    typedef StringTableEntry typeReferenceFilePath;
+    typedef HashMap<typeAssetId, AssetDefinition*> typeDeclaredAssetsHash;
+    typedef HashTable<typeAssetId, typeReferenceFilePath> typeReferencedAssetsHash;
+    typedef HashTable<typeAssetId, typeAssetId> typeAssetDependsOnHash;
+    typedef HashTable<typeAssetId, typeAssetId> typeAssetIsDependedOnHash;
+    typedef HashMap<AssetPtrBase*, AssetPtrCallback*> typeAssetPtrRefreshHash;
+
+    /// Declared assets.
+    typeDeclaredAssetsHash              mDeclaredAssets;
+
+    /// Referenced assets.
+    typeReferencedAssetsHash            mReferencedAssets;
+
+    /// Asset dependencies.
+    typeAssetDependsOnHash              mAssetDependsOn;
+    typeAssetIsDependedOnHash           mAssetIsDependedOn;
+
+    /// Asset tags.
+    SimObjectPtr<AssetTagsManifest>     mAssetTagsManifest;
+    SimObjectPtr<ModuleDefinition>      mAssetTagsModuleDefinition;
+
+    /// Asset pointer refresh notifications.
+    typeAssetPtrRefreshHash             mAssetPtrRefreshNotifications;
+
+    /// Miscellaneous.
+    bool                                mEchoInfo;
+    bool                                mIgnoreAutoUnload;
+    U32                                 mLoadedInternalAssetsCount;
+    U32                                 mLoadedExternalAssetsCount;
+    U32                                 mLoadedPrivateAssetsCount;
+    U32                                 mAcquiredReferenceCount;
+    U32                                 mMaxLoadedInternalAssetsCount;
+    U32                                 mMaxLoadedExternalAssetsCount;
+    U32                                 mMaxLoadedPrivateAssetsCount;
+    Taml                                mTaml;
+
+public:
+    AssetManager();
+    virtual ~AssetManager() {}
+
+    /// SimObject overrides
+    virtual bool onAdd();
+    virtual void onRemove();
+    static void initPersistFields();
+
+    /// Declared assets.
+    bool addModuleDeclaredAssets( ModuleDefinition* pModuleDefinition );
+    bool addDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath );
+    StringTableEntry addPrivateAsset( AssetBase* pAssetBase );
+    bool removeDeclaredAssets( ModuleDefinition* pModuleDefinition );
+    bool removeDeclaredAsset( const char* pAssetId );
+    bool renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
+    StringTableEntry getAssetName( const char* pAssetId );
+    StringTableEntry getAssetDescription( const char* pAssetId );
+    StringTableEntry getAssetCategory( const char* pAssetId );
+    StringTableEntry getAssetType( const char* pAssetId );
+    StringTableEntry getAssetFilePath( const char* pAssetId );
+    StringTableEntry getAssetPath( const char* pAssetId );
+    ModuleDefinition* getAssetModuleDefinition( const char* pAssetId );
+    bool isAssetInternal( const char* pAssetId );
+    bool isAssetPrivate( const char* pAssetId );
+    bool isAssetAutoUnload( const char* pAssetId );
+    bool isAssetLoaded( const char* pAssetId );
+    bool isDeclaredAsset( const char* pAssetId );
+    bool doesAssetDependOn( const char* pAssetId, const char* pDependsOnAssetId );
+    bool isAssetDependedOn( const char* pAssetId, const char* pDependedOnByAssetId );
+
+    /// Referenced assets.
+    bool compileReferencedAssets( ModuleDefinition* pModuleDefinition );
+    bool isReferencedAsset( const char* pAssetId );
+    bool renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
+
+    /// Public asset acquisition.
+    template<typename T> T* acquireAsset( const char* pAssetId )
+    {
+        // Sanity!
+        AssertFatal( pAssetId != NULL, "Cannot acquire NULL asset Id." );
+
+        // Is this an empty asset Id?
+        if ( *pAssetId == 0 )
+        {
+            // Yes, so return nothing.
+            return NULL;
+        }
+
+        // Find asset.
+        AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+        // Did we find the asset?
+        if ( pAssetDefinition == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: Failed to acquire asset Id '%s' as it does not exist.", pAssetId );
+            return NULL;
+        }
+
+        // Is asset loading?
+        if ( pAssetDefinition->mAssetLoading == true )
+        {
+            // Yes, so we've got a circular loop which we cannot resolve!
+            Con::warnf( "Asset Manager: Failed to acquire asset Id '%s' as loading it involves a cyclic dependency on itself which cannot be resolved.", pAssetId );
+            return NULL;
+        }
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printSeparator();
+            Con::printf( "Asset Manager: Started acquiring Asset Id '%s'...", pAssetId );
+        }
+
+        // Is the asset already loaded?
+        if ( pAssetDefinition->mpAssetBase == NULL )
+        {
+            // No, so info
+            if ( mEchoInfo )
+            {
+                // Fetch asset Id.
+                StringTableEntry assetId = StringTable->insert( pAssetId );
+
+                // Find any asset dependencies.
+                typeAssetDependsOnHash::Iterator assetDependenciesItr = mAssetDependsOn.find( assetId );
+
+                // Does the asset have any dependencies?
+                if ( assetDependenciesItr != mAssetDependsOn.end() )
+                {
+                    // Yes, so show all dependency assets.
+                    Con::printf( "Asset Manager: > Found dependencies:" );
+
+                    // Iterate all dependencies.
+                    while( assetDependenciesItr != mAssetDependsOn.end() && assetDependenciesItr->key == assetId )
+                    {
+                        // Info.
+                        Con::printf( "Asset Manager: > Asset Id '%s'", assetDependenciesItr->value );
+
+                        // Next dependency.
+                        assetDependenciesItr++;
+                    }
+                }
+            }
+
+            // Flag asset as loading.
+            pAssetDefinition->mAssetLoading = true;
+
+            // Generate primary asset.
+            pAssetDefinition->mpAssetBase = mTaml.read<T>( pAssetDefinition->mAssetBaseFilePath );
+
+            // Flag asset as finished loading.
+            pAssetDefinition->mAssetLoading = false;
+
+            // Did we generate the asset?
+            if ( pAssetDefinition->mpAssetBase == NULL )
+            {
+                // No, so warn.
+                Con::warnf( "Asset Manager: > Failed to acquire asset Id '%s' as loading the asset file failed to return the asset or the correct asset type: '%s'.",
+                    pAssetId, pAssetDefinition->mAssetBaseFilePath );
+                return NULL;
+            }
+
+            // Increase loaded count.
+            pAssetDefinition->mAssetLoadedCount++;
+
+            // Info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Loading asset into memory as object Id '%d' from file '%s'.",
+                    pAssetDefinition->mpAssetBase->getId(), pAssetDefinition->mAssetBaseFilePath );
+            }
+
+            // Set ownership by asset manager.
+            pAssetDefinition->mpAssetBase->setOwned( this, pAssetDefinition );
+
+            // Is the asset internal?
+            if ( pAssetDefinition->mAssetInternal )
+            {
+                // Yes, so increase internal loaded asset count.
+                if ( ++mLoadedInternalAssetsCount > mMaxLoadedInternalAssetsCount )
+                    mMaxLoadedInternalAssetsCount = mLoadedInternalAssetsCount;
+            }
+            else
+            {
+                // No, so increase external loaded assets count.
+                if ( ++mLoadedExternalAssetsCount > mMaxLoadedExternalAssetsCount )
+                    mMaxLoadedExternalAssetsCount = mLoadedExternalAssetsCount;
+            }
+        }
+        else if ( pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() == 0 )
+        {
+            // Info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Acquiring from idle state." );
+            }
+        }
+
+        // Set acquired asset.
+        T* pAcquiredAsset = dynamic_cast<T*>( (AssetBase*)pAssetDefinition->mpAssetBase );
+
+        // Is asset the correct type?
+        if ( pAcquiredAsset == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: > Failed to acquire asset Id '%s' as it was not the required asset type: '%s'.", pAssetId, pAssetDefinition->mAssetBaseFilePath );
+            return NULL;
+        }
+
+        // Acquire asset reference.
+        pAcquiredAsset->acquireAssetReference();
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: > Finished acquiring asset.  Reference count now '%d'.", pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() );
+            Con::printSeparator();
+        }
+
+        return pAcquiredAsset;
+    }
+
+    /// Private asset acquisition.
+    template<typename T> T* acquireAsPrivateAsset( const char* pAssetId )
+    {
+        // Acquire the asset normally.
+        T* pAsset = acquireAsset<T>( pAssetId );
+
+        // Finish if the asset was not acquired.
+        if ( pAsset == NULL )
+            return NULL;
+
+        // Clone the asset.
+        T* pAssetClone = dynamic_cast<T*>( pAsset->clone() );
+
+        // Sanity!
+        AssertFatal( pAssetClone != NULL, "acquireAsPrivateAsset() - Failed to clone asset type." );
+
+        // Release the public asset.
+        releaseAsset( pAssetId );
+
+        // Add as a private asset.
+        addPrivateAsset( pAssetClone );
+
+        return pAssetClone;
+    }
+
+    bool releaseAsset( const char* pAssetId );
+    void purgeAssets( void );
+
+    /// Asset deletion.
+    bool deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies );
+
+    // Asset refresh notification.
+    bool refreshAsset( const char* pAssetId );
+    void refreshAllAssets( const bool includeUnloaded = false );
+    void registerAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase, AssetPtrCallback* pCallback );
+    void unregisterAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase );
+
+    /// Asset tags.
+    bool loadAssetTags( ModuleDefinition* pModuleDefinition );
+    bool saveAssetTags( void );
+    bool restoreAssetTags( void );
+    inline AssetTagsManifest* getAssetTags( void ) const { return mAssetTagsManifest; }
+
+    /// Info.
+    inline U32 getDeclaredAssetCount( void ) const { return (U32)mDeclaredAssets.size(); }
+    inline U32 getReferencedAssetCount( void ) const { return (U32)mReferencedAssets.size(); }
+    inline U32 getLoadedInternalAssetCount( void ) const { return mLoadedInternalAssetsCount; }
+    inline U32 getLoadedExternalAssetCount( void ) const { return mLoadedExternalAssetsCount; }
+    inline U32 getLoadedPrivateAssetCount( void ) const { return mLoadedPrivateAssetsCount; }
+    inline U32 getMaxLoadedInternalAssetCount( void ) const { return mMaxLoadedInternalAssetsCount; }
+    inline U32 getMaxLoadedExternalAssetCount( void ) const { return mMaxLoadedExternalAssetsCount; }
+    inline U32 getMaxLoadedPrivateAssetCount( void ) const { return mMaxLoadedPrivateAssetsCount; }
+    void dumpDeclaredAssets( void ) const;
+
+    /// Total acquired asset references.
+    inline void acquireAcquiredReferenceCount( void ) { mAcquiredReferenceCount++; }
+    inline void releaseAcquiredReferenceCount( void ) { AssertFatal( mAcquiredReferenceCount != 0, "AssetManager: Invalid acquired reference count." ); mAcquiredReferenceCount--; }
+    inline U32 getAcquiredReferenceCount( void ) const { return mAcquiredReferenceCount; }
+
+    /// Asset queries.
+    S32 findAllAssets( AssetQuery* pAssetQuery, const bool ignoreInternal = true, const bool ignorePrivate = true );
+    S32 findAssetName( AssetQuery* pAssetQuery, const char* pAssetName, const bool partialName = false );
+    S32 findAssetCategory( AssetQuery* pAssetQuery, const char* pAssetCategory, const bool assetQueryAsSource = false );
+    S32 findAssetAutoUnload( AssetQuery* pAssetQuery, const bool assetAutoUnload, const bool assetQueryAsSource = false );
+    S32 findAssetInternal( AssetQuery* pAssetQuery, const bool assetInternal, const bool assetQueryAsSource = false );
+    S32 findAssetPrivate( AssetQuery* pAssetQuery, const bool assetPrivate, const bool assetQueryAsSource = false );
+    S32 findAssetType( AssetQuery* pAssetQuery, const char* pAssetType, const bool assetQueryAsSource = false );
+    S32 findAssetDependsOn( AssetQuery* pAssetQuery, const char* pAssetId );
+    S32 findAssetIsDependedOn( AssetQuery* pAssetQuery, const char* pAssetId );
+    S32 findInvalidAssetReferences( AssetQuery* pAssetQuery );
+    S32 findTaggedAssets( AssetQuery* pAssetQuery, const char* pAssetTagNames, const bool assetQueryAsSource = false );
+    S32 findAssetLooseFile( AssetQuery* pAssetQuery, const char* pLooseFile, const bool assetQueryAsSource = false );
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( AssetManager );
+
+private:
+    bool scanDeclaredAssets( const char* pPath, const char* pExtension, const bool recurse, ModuleDefinition* pModuleDefinition );
+    bool scanReferencedAssets( const char* pPath, const char* pExtension, const bool recurse );
+    AssetDefinition* findAsset( const char* pAssetId );
+    void addReferencedAsset( StringTableEntry assetId, StringTableEntry referenceFilePath );
+    void renameAssetReferences( StringTableEntry assetIdFrom, StringTableEntry assetIdTo );
+    void removeAssetReferences( StringTableEntry assetId );
+    void renameAssetDependencies( StringTableEntry assetIdFrom, StringTableEntry assetIdTo );
+    void removeAssetDependencies( const char* pAssetId );
+    void removeAssetLooseFiles( const char* pAssetId );
+    void unloadAsset( AssetDefinition* pAssetDefinition );
+
+    /// Module callbacks.
+    virtual void onModulePreLoad( ModuleDefinition* pModuleDefinition );
+    virtual void onModulePreUnload( ModuleDefinition* pModuleDefinition );
+    virtual void onModulePostUnload( ModuleDefinition* pModuleDefinition );
+};
+
+//-----------------------------------------------------------------------------
+
+extern AssetManager AssetDatabase;
+
+#endif // _ASSET_MANAGER_H_

+ 811 - 0
Engine/source/assets/assetManager_ScriptBinding.h

@@ -0,0 +1,811 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#include "console/engineAPI.h"
+#include "assetBase.h"
+#include "assetManager.h"
+#include "module/moduleDefinition.h"
+#include "console/sim.h"
+
+DefineEngineMethod(AssetManager, compileReferencedAssets, bool, (const char* moduleDefinition), (""),
+   "Compile the referenced assets determined by the specified module definition.\n"
+   "@param moduleDefinition The module definition specifies the asset manifest.\n"
+   "@return Whether the compilation was successful or not.\n")
+{
+    // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::compileReferencedAssets() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Compile referenced assets.
+    return object->compileReferencedAssets( pModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, addModuleDeclaredAssets, bool, (const char* moduleDefinition), (""),
+   "Add any the declared assets specified by the module definition.\n"
+   "@param moduleDefinition The module definition specifies the asset manifest.\n"
+   "@return Whether adding declared assets was successful or not.\n")
+{
+   // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::addDeclaredAssets() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Add module declared assets.
+    return object->addModuleDeclaredAssets( pModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, addDeclaredAsset, bool, (const char* moduleDefinition, const char* assetFilePath), ("", ""),
+   "Add the specified asset against the specified module definition.\n"
+   "@param moduleDefinition The module definition that may contain declared assets.\n"
+   "@return Whether adding declared assets was successful or not.\n")
+{
+   // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::addDeclaredAsset() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Fetch asset file-path.
+    const char* pAssetFilePath = assetFilePath;
+
+    // Add declared asset.
+    return object->addDeclaredAsset( pModuleDefinition, pAssetFilePath );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, addPrivateAsset, String, (const char* assetObject), (""),
+   "Adds a private asset object.\n"
+   "@param assetObject The asset object to add as a private asset.\n"
+   "@return The allocated private asset Id.\n")
+{
+    // Fetch asset.
+   AssetBase* pAssetBase;
+   Sim::findObject(assetObject, pAssetBase);
+
+    // Did we find the asset?
+    if ( pAssetBase == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::addPrivateAsset() - Could not find the asset '%s'.", assetObject);
+        return StringTable->EmptyString();
+    }
+
+    // Add private asset.
+    return object->addPrivateAsset( pAssetBase );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, removeDeclaredAssets, bool, (const char* moduleDefinition), (""),
+   "Remove any the declared assets specified by the module definition.\n"
+   "@param moduleDefinition The module definition that may contain declared assets.\n"
+   "@return Whether removing declared assets was successful or not.\n")
+{
+    // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::removeDeclaredAssets() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Remove declared assets.
+    return object->removeDeclaredAssets( pModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, removeDeclaredAsset, bool, (const char* assetId), (""),
+   "Remove the specified declared asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether removing the declared asset was successful or not.\n")
+{
+    // Remove the declared asset Id.
+   return object->removeDeclaredAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetName, String, (const char* assetId), (""),
+   "Gets the asset name from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset name from the specified asset Id.\n")
+{
+   return object->getAssetName(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetDescription, String, (const char* assetId), (""),
+   "Gets the asset description from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset description from the specified asset Id.\n")
+{
+   return object->getAssetDescription(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetCategory, String, (const char* assetId), (""),
+   "Gets the asset category from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset category from the specified asset Id.\n")
+{
+   return object->getAssetCategory(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetType, String, (const char* assetId), (""),
+   "Gets the asset type from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset type from the specified asset Id.\n")
+{
+   return object->getAssetType(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetFilePath, String, (const char* assetId), (""),
+   "Gets the asset file-path from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset file - path from the specified asset Id.\n")
+{
+   return object->getAssetFilePath(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetPath, String, (const char* assetId), (""),
+   "Gets the asset path (not including the asset file) from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset path(not including the asset file) from the specified asset Id.\n")
+{
+   return object->getAssetPath(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetModule, String, (const char* assetId), (""),
+   "Gets the module definition where the the specified asset Id is located.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The module definition where the the specified asset Id is located.\n")
+{
+    // Fetch module definition.
+   ModuleDefinition* pModuleDefinition = object->getAssetModuleDefinition(assetId);
+
+    return pModuleDefinition == NULL ? StringTable->EmptyString() : pModuleDefinition->getIdString();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetInternal, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is internal or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is internal or not.\n")
+{
+   return object->isAssetInternal(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetPrivate, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is private or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is private or not.\n")
+{
+   return object->isAssetPrivate(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetAutoUnload, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is auto - unload or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is auto-unload or not.\n")
+{
+   return object->isAssetAutoUnload(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetLoaded, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is loaded or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is loaded or not.\n")
+{
+   return object->isAssetLoaded(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isDeclaredAsset, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is declared or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is declared or not.\n")
+{
+   return object->isDeclaredAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isReferencedAsset, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is referenced or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is referenced or not.\n")
+{
+   return object->isReferencedAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, renameDeclaredAsset, bool, (const char* assetIdFrom, const char* assetIdTo), ("", ""),
+   "Rename declared asset Id.\n"
+   "@param assetIdFrom The selected asset Id to rename from.\n"
+   "@param assetIdFrom The selected asset Id to rename to.\n"
+   "@return Whether the rename was successful or not.\n")
+{
+   return object->renameDeclaredAsset(assetIdFrom, assetIdTo);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, renameReferencedAsset, bool, (const char* assetIdFrom, const char* assetIdTo), ("", ""),
+   "Rename referenced asset Id. \n"
+   "@param assetIdFrom The selected asset Id to rename from.\n"
+   "@param assetIdFrom The selected asset Id to rename to.\n"
+   "@return Whether the rename was successful or not.\n")
+{
+   return object->renameReferencedAsset(assetIdFrom, assetIdTo);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, acquireAsset, String, (const char* assetId, bool asPrivate), ("", false),
+   "Acquire the specified asset Id.\n"
+   "You must release the asset once you're finish with it using 'releaseAsset'.\n"
+   "@param assetId The selected asset Id.\n"
+   "@param asPrivate Whether to acquire the asset Id as a private asset.\n"
+   "@return The acquired asset or NULL if not acquired.\n")
+{
+    // Fetch asset Id.
+   const char* pAssetId = assetId;
+
+    // Reset asset reference.
+    AssetBase* pAssetBase = NULL;
+
+    // Acquire private asset?
+    if ( asPrivate )
+    {
+        // Acquire private asset.
+        pAssetBase = object->acquireAsPrivateAsset<AssetBase>( pAssetId );
+    }
+    else
+    {
+        // Acquire public asset.
+        pAssetBase = object->acquireAsset<AssetBase>( pAssetId );
+    }
+
+    return pAssetBase != NULL ? pAssetBase->getIdString() : StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, releaseAsset, bool, (const char* assetId), (""),
+   "Release the specified asset Id.\n"
+   "The asset should have been acquired using 'acquireAsset'.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the asset was released or not.\n")
+{
+    // Release asset.
+   return object->releaseAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, purgeAssets, void, (),,
+   "Purge all assets that are not referenced even if they are set to not auto-unload.\n"
+   "Assets can be in this state because they are either set to not auto-unload or the asset manager has/is disabling auto-unload.\n"
+   "@return No return value.\n")
+{
+    // Purge assets.
+    object->purgeAssets();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, deleteAsset, bool, (const char* assetId, bool deleteLooseFiles, bool deleteDependencies), ("", false, false),
+   "Deletes the specified asset Id and optionally its loose files and asset dependencies.\n"
+   "@param assetId The selected asset Id.\n"
+   "@param deleteLooseFiles Whether to delete an assets loose files or not.\n"
+   "@param deleteDependencies Whether to delete assets that depend on this asset or not.\n"
+   "@return Whether the asset deletion was successful or not.  A failure only indicates that the specified asset was not deleted but dependent assets and their loose files may have being deleted.\n")
+{
+    // Fetch asset Id.
+   const char* pAssetId = assetId;
+
+    // Delete asset.
+    return object->deleteAsset( pAssetId, deleteLooseFiles, deleteDependencies );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, refreshAsset, void, (const char* assetId), (""),
+   "Refresh the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return No return value.\n")
+{
+   object->refreshAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, refreshAllAssets, void, (bool includeUnloaded), (false),
+   "Refresh all declared assets.\n"
+   "@param Whether to include currently unloaded assets in the refresh or not.  Optional: Defaults to false.\n"
+   "Refreshing all assets can be an expensive (time-consuming) operation to perform.\n"
+   "@return No return value.\n")
+{
+    // Refresh assets
+    object->refreshAllAssets(includeUnloaded);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, saveAssetTags, bool, (),,
+   "Save the currently loaded asset tags manifest.\n"
+   "@return Whether the save was successful or not.\n")
+{
+    // Save asset tags.
+    return object->saveAssetTags();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, restoreAssetTags, bool, (),,
+   "Restore the currently loaded asset tags manifest from disk (replace anything in memory).\n"
+   "@return Whether the restore was successful or not.\n")
+{
+    // Restore asset tags.
+    return object->restoreAssetTags();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetTags, S32, (), ,
+   "Gets the currently loaded asset tags manifest.\n"
+   "@return The currently loaded asset tags manifest or zero if not loaded.\n")
+{
+    // Fetch the asset tags manifest.
+    AssetTagsManifest* pAssetTagsManifest = object->getAssetTags();
+
+    return pAssetTagsManifest == NULL ? 0 : pAssetTagsManifest->getId();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAllAssets, S32, (const char* assetQuery, bool ignoreInternal, bool ignorePrivate), ("", true, true),
+   "Performs an asset query searching for all assets optionally ignoring internal assets.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param ignoreInternal Whether to ignore internal assets or not.  Optional: Defaults to true.\n"
+   "@param ignorePrivate Whether to ignore private assets or not.  Optional: Defaults to true.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAllAssets() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAllAssets( pAssetQuery, ignoreInternal, ignorePrivate );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetName, S32, (const char* assetQuery, const char* assetName, bool partialName), ("", "", false),
+   "Performs an asset query searching for the specified asset name.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetName The asset name to search for.  This may be a partial name if 'partialName' is true.\n"
+   "@param partialName Whether the asset name is to be used as a partial name or not.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetName() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset name.
+    const char* pAssetName = assetName;
+
+    // Perform query.
+    return object->findAssetName( pAssetQuery, pAssetName, partialName );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetCategory, S32, (const char* assetQuery, const char* assetCategory, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified asset category.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetCategory The asset category to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetCategory() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset category.
+    const char* pAssetCategory = assetCategory;
+
+    // Perform query.
+    return object->findAssetCategory( pAssetQuery, pAssetCategory, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetAutoUnload, S32, (const char* assetQuery, bool assetAutoUnload, bool assetQueryAsSource), ("", false, false),
+   "Performs an asset query searching for the specified asset auto-unload flag.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetInternal The asset internal flag to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetAutoUnload() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAssetAutoUnload( pAssetQuery, assetAutoUnload, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetInternal, S32, (const char* assetQuery, bool assetInternal, bool assetQueryAsSource), ("", false, false),
+   "Performs an asset query searching for the specified asset internal flag.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetInternal The asset internal flag to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetInternal() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAssetInternal( pAssetQuery, assetInternal, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetPrivate, S32, (const char* assetQuery, bool assetPrivate, bool assetQueryAsSource), ("", false, false),
+   "Performs an asset query searching for the specified asset private flag.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetPrivate The asset private flag to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetPrivate() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAssetInternal( pAssetQuery, assetPrivate, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetType, S32, (const char* assetQuery, const char* assetType, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified asset type.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetType The asset type to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetType() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset type.
+    const char* pAssetType = assetType;
+
+    // Perform query.
+    return object->findAssetType( pAssetQuery, pAssetType, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetDependsOn, S32, (const char* assetQuery, const char* assetId), ("", ""),
+   "Performs an asset query searching for asset Ids that the specified asset Id depends on.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetId The asset Id to query for any asset Ids that it depends on.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetDependsOn() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset Id.
+    const char* pAssetId = assetId;
+
+    // Perform query.
+    return object->findAssetDependsOn( pAssetQuery, pAssetId );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetIsDependedOn, S32, (const char* assetQuery, const char* assetId), ("", ""),
+   "Performs an asset query searching for asset Ids that depend on the specified asset Id.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetId The asset Id to query for any asset Ids that may depend on it.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetIsDependedOn() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset Id.
+    const char* pAssetId = assetId;
+
+    // Perform query.
+    return object->findAssetIsDependedOn( pAssetQuery, pAssetId );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findInvalidAssetReferences, S32, (const char* assetQuery), (""),
+   "Performs an asset query searching for invalid asset references.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@return The number of asset Ids found that are invalid or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findInvalidAssetReferences() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findInvalidAssetReferences( pAssetQuery );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findTaggedAssets, S32, (const char* assetQuery, const char* assetTagNames, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified asset tag name(s).\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetTagNames The asset tag name or names to search for.  Multiple names can be specified using comma, space, tab or newline separation.  Tags use an OR operation i.e. only assets tagged with ANY of the specified tags will be returned.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findTaggedAssets() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset tag name(s).
+    const char* pAssetTagNames = assetTagNames;
+
+    // Perform query.
+    return object->findTaggedAssets( pAssetQuery, pAssetTagNames, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetLooseFile, S32, (const char* assetQuery, const char* assetLooseFile, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified loose file.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetLooseFile The loose-file used by the asset to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetLooseFile() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset loose file.
+    const char* pAssetLooseFile = assetLooseFile;
+
+    // Perform query.
+    return object->findAssetLooseFile( pAssetQuery, pAssetLooseFile, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getDeclaredAssetCount, bool, (),,
+   "Gets the number of declared assets.\n"
+   "@return Returns the number of declared assets.\n")
+{
+    return object->getDeclaredAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getReferencedAssetCount, bool, (), ,
+   "Gets the number of asset referenced.\n"
+   "@return Returns the number of asset references.\n")
+{
+    return object->getReferencedAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getLoadedInternalAssetCount, bool, (), ,
+   "Gets the number of loaded internal assets.\n"
+   "@return Returns the number of loaded internal assets.\n")
+{
+    return object->getLoadedInternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getMaxLoadedInternalAssetCount, bool, (), ,
+   "Gets the maximum number of loaded internal assets.\n"
+   "@return Returns the maximum number of loaded internal assets.\n")
+{
+    return object->getMaxLoadedInternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getLoadedExternalAssetCount, bool, (), ,
+   "Gets the number of loaded external assets.\n"
+   "@return Returns the number of loaded external assets.\n")
+{
+    return object->getLoadedExternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getMaxLoadedExternalAssetCount, bool, (), ,
+   "Gets the maximum number of loaded external assets.\n"
+   "@return Returns the maximum number of loaded external assets.\n")
+{
+    return object->getMaxLoadedExternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, dumpDeclaredAssets, void, (), ,
+   "Dumps a breakdown of all declared assets.\n"
+   "@return No return value.\n")
+{
+    return object->dumpDeclaredAssets();
+}

+ 184 - 0
Engine/source/assets/assetPtr.h

@@ -0,0 +1,184 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_PTR_H_
+#define _ASSET_PTR_H_
+
+#ifndef _ASSET_MANAGER_H_
+#include "assetManager.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class AssetPtrCallback
+{
+    friend class AssetManager;
+
+protected:
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase ) = 0;    
+};
+
+//-----------------------------------------------------------------------------
+
+class AssetPtrBase
+{
+public:
+    AssetPtrBase() {};
+    virtual ~AssetPtrBase()
+    {
+        // Un-register any notifications.
+        unregisterRefreshNotify();
+    };
+
+    /// Referencing.
+    virtual void clear( void ) = 0;
+    virtual void setAssetId( const char* pAssetId ) = 0;
+    virtual StringTableEntry getAssetId( void ) const = 0;
+    virtual StringTableEntry getAssetType( void ) const = 0;
+    virtual bool isAssetId( const char* pAssetId ) const = 0;
+
+    /// Validity.
+    virtual bool isNull( void ) const = 0;
+    virtual bool notNull( void ) const = 0;
+
+    /// Notification.
+    inline void registerRefreshNotify( AssetPtrCallback* pCallback )
+    {
+        // Sanity!
+        AssertFatal( AssetDatabase.isProperlyAdded(), "AssetPtrBase::registerRefreshNotify() - Cannot register an asset pointer with the asset system." );
+
+        // register refresh notify.
+        AssetDatabase.registerAssetPtrRefreshNotify( this, pCallback );
+    }
+
+    void unregisterRefreshNotify( void )
+    {
+        // Un-register the refresh notify if the asset system is available.
+        if ( AssetDatabase.isProperlyAdded() )
+            AssetDatabase.unregisterAssetPtrRefreshNotify( this );
+    }
+};
+
+//-----------------------------------------------------------------------------
+
+template<typename T> class AssetPtr : public AssetPtrBase
+{
+private:
+    SimObjectPtr<T> mpAsset;
+
+public:
+    AssetPtr() {}
+    AssetPtr( const char* pAssetId )
+    {
+        // Finish if this is an invalid asset Id.
+        if ( pAssetId == NULL || *pAssetId == 0 )
+            return;
+
+        // Acquire asset.
+        mpAsset = AssetDatabase.acquireAsset<T>( pAssetId );
+    }
+    AssetPtr( const AssetPtr<T>& assetPtr )
+    {
+        // Does the asset pointer have an asset?
+        if ( assetPtr.notNull() )
+        {
+            // Yes, so acquire the asset.
+            mpAsset = AssetDatabase.acquireAsset<T>( assetPtr->getAssetId() );
+        }
+    }
+    virtual ~AssetPtr()
+    {
+        // Do we have an asset?
+        if ( notNull() )
+        {
+            // Yes, so release it.
+            AssetDatabase.releaseAsset( mpAsset->getAssetId() );
+        }
+    }
+
+    /// Assignment.
+    AssetPtr<T>& operator=( const char* pAssetId )
+    {
+        // Do we have an asset?
+        if ( notNull() )
+        {
+            // Yes, so finish if the asset Id is already assigned.
+            if ( isAssetId( pAssetId ) )
+                return *this;
+
+            // No, so release it.
+            AssetDatabase.releaseAsset( mpAsset->getAssetId() );
+        }
+
+        // Is the asset Id at least okay to attempt to acquire the asset?
+        if ( pAssetId != NULL && *pAssetId != 0 )
+        {
+            // Yes, so acquire the asset.
+            mpAsset = AssetDatabase.acquireAsset<T>( pAssetId );
+        }
+        else
+        {
+            // No, so remove reference.
+            mpAsset = NULL;
+        }
+
+        // Return Reference.
+        return *this;
+    }
+
+    AssetPtr<T>& operator=( const AssetPtr<T>& assetPtr )
+    {
+        // Set asset pointer.
+        *this = assetPtr->getAssetId();
+
+        // Return Reference.
+        return *this;
+    }
+
+    /// Referencing.
+    virtual void clear( void )
+    {
+        // Do we have an asset?
+        if ( notNull() )
+        {
+            // Yes, so release it.
+            AssetDatabase.releaseAsset( mpAsset->getAssetId() );
+        }
+
+        // Reset the asset reference.
+        mpAsset = NULL;
+    }
+
+    T* operator->( void ) const { return mpAsset; }
+    T& operator*( void ) const { return *mpAsset; }
+    operator T*( void ) const { return mpAsset; }
+    virtual void setAssetId( const char* pAssetId ) { *this = pAssetId; }
+    virtual StringTableEntry getAssetId( void ) const { return isNull() ? StringTable->EmptyString() : mpAsset->getAssetId(); }
+    virtual StringTableEntry getAssetType(void) const { return isNull() ? StringTable->EmptyString() : mpAsset->getClassName(); }
+    virtual bool isAssetId( const char* pAssetId ) const { return pAssetId == NULL ? isNull() : getAssetId() == StringTable->insert(pAssetId); }
+
+    /// Validity.
+    virtual bool isNull( void ) const { return mpAsset.isNull(); }
+    virtual bool notNull( void ) const { return !mpAsset.isNull(); }
+};
+
+#endif // _ASSET_PTR_H_

+ 121 - 0
Engine/source/assets/assetQuery.cpp

@@ -0,0 +1,121 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_QUERY_H_
+#include "assetQuery.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _TAML_CUSTOM_H_
+#include "persistence/taml/tamlCustom.h"
+#endif
+
+// Script bindings.
+#include "assetQuery_ScriptBinding.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( AssetQuery );
+
+//-----------------------------------------------------------------------------
+
+void AssetQuery::initPersistFields()
+{
+    // Call parent.
+    Parent::initPersistFields();
+
+    addProtectedField("Count", TypeS32, 0, &defaultProtectedSetFn, &getCount, &writeCount, "Gets the number of results in the asset query.");
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetQuery::onTamlCustomWrite( TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomWrite( customNodes );
+
+    // Add node.
+    TamlCustomNode* pCustomNode = customNodes.addNode( ASSETQUERY_RESULTS_NODE_NAME );
+
+    // Finish if no assets.
+    if (mAssetList.size() == 0)
+        return;
+
+    // Iterate asset.
+    for (Vector<StringTableEntry>::iterator assetItr = mAssetList.begin(); assetItr != mAssetList.end(); ++assetItr)
+    {
+        // Add asset node.
+        TamlCustomNode* pAssetNode = pCustomNode->addNode( ASSETQUERY_ASSETNODE_NAME );
+
+        // Add field.
+        pAssetNode->addField( ASSETQUERY_ASSETID_FIELD_NAME, *assetItr );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetQuery::onTamlCustomRead( const TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomRead( customNodes );
+
+    // Find custom node name.
+    const TamlCustomNode* pResultsNode = customNodes.findNode( ASSETQUERY_RESULTS_NODE_NAME );
+
+    // Finish if we don't have a results name.
+    if ( pResultsNode == NULL )
+        return;
+
+    // Fetch node name.
+    StringTableEntry assetNodeName = StringTable->insert( ASSETQUERY_ASSETNODE_NAME );
+
+    // Fetch children asset nodes.
+    const TamlCustomNodeVector& assetNodes = pResultsNode->getChildren();
+
+    // Iterate asset nodes.
+    for( TamlCustomNodeVector::const_iterator assetNodeItr = assetNodes.begin(); assetNodeItr != assetNodes.end(); ++assetNodeItr )
+    {
+        // Fetch asset node.
+        const TamlCustomNode* pAssetNode = *assetNodeItr;
+
+        // Skip if an unknown node name.
+        if ( pAssetNode->getNodeName() != assetNodeName )
+            continue;
+
+        // Fetch field.
+        const TamlCustomField* pField = pAssetNode->findField( ASSETQUERY_ASSETID_FIELD_NAME );
+
+        // Do we find the field?
+        if ( pField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetQuery::onTamlCustomRead() - Could not find '%s' field.", ASSETQUERY_ASSETID_FIELD_NAME );
+            continue;
+        }
+
+        // Store asset.
+        mAssetList.push_back(pField->getFieldValue());
+    }
+}

+ 90 - 0
Engine/source/assets/assetQuery.h

@@ -0,0 +1,90 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_QUERY_H_
+#define _ASSET_QUERY_H_
+
+#ifndef _SIMBASE_H_
+#include "console/simBase.h"
+#endif
+
+#ifndef _TVECTOR_H_
+#include "core/util/tVector.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "core/strings/stringUnit.h"
+#endif
+
+#ifndef _TAML_CUSTOM_H_
+#include "persistence/taml/tamlCustom.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+#define ASSETQUERY_RESULTS_NODE_NAME     "Results"
+#define ASSETQUERY_ASSETNODE_NAME        "Asset"
+#define ASSETQUERY_ASSETID_FIELD_NAME   "AssetId"
+
+//-----------------------------------------------------------------------------
+
+class AssetQuery : public SimObject 
+{
+private:
+    typedef SimObject Parent;
+
+protected:
+    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)->mAssetList.size()); }
+    static bool writeCount( void* obj, StringTableEntry pFieldName ) { return false; }
+
+public:
+    AssetQuery() {}
+    virtual ~AssetQuery() {}
+
+    /// SimObject overrides
+    static void initPersistFields();
+
+    Vector<StringTableEntry> mAssetList;
+
+    /// Whether asset is contained or not.
+    inline bool containsAsset( StringTableEntry assetId )
+    {
+       for (Vector<StringTableEntry>::const_iterator assetItr = mAssetList.begin(); assetItr != mAssetList.end(); ++assetItr)
+        {
+            if ( *assetItr == assetId )
+                return true;
+        }
+        return false;
+    }
+
+    /// Set assets.
+    inline void set( const AssetQuery& assetQuery ) { this->mAssetList = assetQuery.mAssetList; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( AssetQuery );
+};
+
+#endif // _ASSET_QUERY_H_
+

+ 85 - 0
Engine/source/assets/assetQuery_ScriptBinding.h

@@ -0,0 +1,85 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_QUERY_H_
+#include "assets/assetQuery.h"
+#endif
+
+#include "console/engineAPI.h"
+
+DefineConsoleMethod(AssetQuery, clear, void, (),,"Clears all asset Id results."
+   "Clears all asset Id results.\n"
+   "@return () No return value.\n")
+{
+   object->mAssetList.clear();
+}
+
+//-----------------------------------------------------------------------------
+
+
+DefineConsoleMethod(AssetQuery, set, bool, (S32 queryId), ,
+   "Sets the asset query to a copy of the specified asset query.\n"
+   "@param assetQuery The asset query to copy.\n"
+   "@return Whether the operation succeeded or not.\n")
+{
+    // Find asset query.
+    AssetQuery* pAssetQuery;
+
+    if (!Sim::findObject(queryId, pAssetQuery))
+    {
+       // No, so warn.
+       Con::warnf("AssetQuery::set() - Could not find asset query '%i'.", queryId);
+       return false;
+    }
+
+    // Set asset query.
+    object->set( *pAssetQuery );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleMethod(AssetQuery, getCount, S32, (), , 
+   "Gets the count of asset Id results.\n"
+   "@return (int)The count of asset Id results.\n")
+{
+   return object->mAssetList.size();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleMethod(AssetQuery, getAsset, const char*, (S32 resultIndex), (-1), 
+   "Gets the asset Id at the specified query result index.\n"
+   "@param resultIndex The query result index to use.\n"
+   "@return (assetId)The asset Id at the specified index or NULL if not valid.\n")
+{
+    // Is index within bounds?
+   if (resultIndex >= object->mAssetList.size())
+    {
+        // No, so warn.
+        Con::warnf("AssetQuery::getAsset() - Result index '%s' is out of bounds.", resultIndex);
+        return StringTable->EmptyString();
+    }
+
+    return object->mAssetList[resultIndex];
+}

+ 564 - 0
Engine/source/assets/assetTagsManifest.cpp

@@ -0,0 +1,564 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_TAGS_MANIFEST_H_
+#include "assetTagsManifest.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+// Script binding.
+#include "assetTagsManifest_ScriptBinding.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( AssetTagsManifest );
+
+//-----------------------------------------------------------------------------
+
+AssetTagsManifest::AssetTagsManifest()
+{
+}
+
+//-----------------------------------------------------------------------------
+
+AssetTagsManifest::~AssetTagsManifest()
+{
+    // Iterate tags.
+    for( typeTagNameHash::iterator tagNameItr = mTagNameDatabase.begin(); tagNameItr != mTagNameDatabase.end(); ++tagNameItr )
+    {
+        // Delete asset tag.
+        delete tagNameItr->value;
+    }
+
+    // Clear database.
+    mTagNameDatabase.clear();
+    mAssetToTagDatabase.clear();
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetTagsManifest::fetchTagName( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    return StringTable->insert( pTagName, true );
+}
+
+//-----------------------------------------------------------------------------
+
+AssetTagsManifest::AssetTag* AssetTagsManifest::findAssetTag( const char* pTagName )
+{
+    // Fetch tag name.
+    StringTableEntry tagName = fetchTagName( pTagName );
+
+    // Finish if the tag already exists.
+    typeTagNameHash::iterator tagNameItr = mTagNameDatabase.find( tagName );
+
+    return tagNameItr == mTagNameDatabase.end() ? NULL : tagNameItr->value;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetTagsManifest::renameAssetId( const char* pAssetIdFrom, const char* pAssetIdTo )
+{
+    // Sanity!
+    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
+    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
+
+    // Fetch asset Ids.
+    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
+    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
+
+    while( true )
+    {
+        // Find asset Id.
+        typeAssetToTagHash::Iterator assetIdItr = mAssetToTagDatabase.find( assetIdFrom );
+
+        // Finish if no asset Id to rename.
+        if ( assetIdItr == mAssetToTagDatabase.end() )
+            return;
+
+        // Fetch asset tag.
+        AssetTag* pAssetTag = assetIdItr->value;
+
+        // Untag old asset Id.
+        untag( assetIdFrom, pAssetTag->mTagName );
+
+        // Tag new asset Id.
+        tag( assetIdTo, pAssetTag->mTagName );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetTagsManifest::onTamlCustomWrite( TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomWrite( customNodes );
+
+    // Finish if no tags.
+    if ( mTagNameDatabase.size() == 0 )
+        return;
+
+    // Add node.
+    TamlCustomNode* pTagsNode = customNodes.addNode( ASSETTAGS_TAGS_NODE_NAME );
+
+    // Iterate tags.
+    for( typeTagNameHash::iterator tagItr = mTagNameDatabase.begin(); tagItr != mTagNameDatabase.end(); ++tagItr )
+    {
+        // Add tag node.
+        TamlCustomNode* pTagNode = pTagsNode->addNode( ASSETTAGS_TAGS_TYPE_NAME );
+
+        // Add fields.
+        pTagNode->addField( ASSETTAGS_TAGS_NAME_FIELD, tagItr->key );
+    }
+
+    // Add node.
+    TamlCustomNode* pAssetTagsNode = customNodes.addNode( ASSETTAGS_ASSETS_NODE_NAME );
+
+    // Iterate asset locations.
+    for( typeAssetToTagHash::Iterator assetTagItr = mAssetToTagDatabase.begin(); assetTagItr != mAssetToTagDatabase.end(); ++assetTagItr )
+    {
+        // Add asset tag node.
+        TamlCustomNode* pAssetNode = pAssetTagsNode->addNode( ASSETTAGS_ASSETS_TYPE_NAME );
+
+        // Add fields.
+        pAssetNode->addField( ASSETTAGS_ASSETS_ASSETID_FIELD, assetTagItr->key );
+        pAssetNode->addField( ASSETTAGS_ASSETS_TAG_FIELD, assetTagItr->value->mTagName );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetTagsManifest::onTamlCustomRead( const TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomRead( customNodes );
+
+    // Find tags nodes.
+    const TamlCustomNode* pTagProperty = customNodes.findNode( ASSETTAGS_TAGS_NODE_NAME );
+
+    // Finish if we don't have a tags node name.
+    if ( pTagProperty == NULL )
+        return;
+
+    // Fetch node name.
+    StringTableEntry tagNodeName = StringTable->insert( ASSETTAGS_TAGS_TYPE_NAME );
+
+    // Fetch children asset nodes.
+    const TamlCustomNodeVector& tagNodes = pTagProperty->getChildren();
+
+    // Iterate tag nodes.
+    for( TamlCustomNodeVector::const_iterator tagNodeItr = tagNodes.begin(); tagNodeItr != tagNodes.end(); ++tagNodeItr )
+    {
+        // Fetch tag node.
+        const TamlCustomNode* pTagNode = *tagNodeItr;
+
+        // Skip if an unknown node name.
+        if ( pTagNode->getNodeName() != tagNodeName )
+            continue;
+
+        // Fetch "Name" field.
+        const TamlCustomField* pTagNameField = pTagNode->findField( ASSETTAGS_TAGS_NAME_FIELD );
+
+        // Do we find the field?
+        if ( pTagNameField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Could not find '%s' field.", ASSETTAGS_TAGS_NAME_FIELD );
+            continue;
+        }
+
+        // Create the tag.
+        createTag( pTagNameField->getFieldValue() );
+    }
+
+    // Find asset tags node.
+    const TamlCustomNode* pAssetTagProperty = customNodes.findNode( ASSETTAGS_ASSETS_NODE_NAME );
+
+    // Finish if we don't have an asset tags node name.
+    if ( pAssetTagProperty == NULL )
+        return;
+
+    // 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( TamlCustomNodeVector::const_iterator assetTagNodeItr = assetTagNodes.begin(); assetTagNodeItr != assetTagNodes.end(); ++assetTagNodeItr )
+    {
+        // Fetch asset node.
+        const TamlCustomNode* pAssetTagNode = *assetTagNodeItr;
+
+        // Skip if an unknown node name.
+        if ( pAssetTagNode->getNodeName() != assetTagNodeName )
+            continue;
+
+        // Fetch "AssetId" field.
+        const TamlCustomField* pAssetIdField = pAssetTagNode->findField( ASSETTAGS_ASSETS_ASSETID_FIELD );
+
+        // Do we find the field?
+        if ( pAssetIdField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Could not find '%s' field.", ASSETTAGS_ASSETS_ASSETID_FIELD );
+            continue;
+        }
+
+        // Fetch "Tag" field.
+        const TamlCustomField* pTagField = pAssetTagNode->findField( ASSETTAGS_ASSETS_TAG_FIELD );
+
+        // Do we find the field?
+        if ( pTagField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Could not find '%s' field.", ASSETTAGS_ASSETS_TAG_FIELD );
+            continue;
+        }
+
+        // Tag the asset.
+        tag( pAssetIdField->getFieldValue(), pTagField->getFieldValue() );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+const AssetTagsManifest::AssetTag* AssetTagsManifest::createTag( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Finish if the tag already exists.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Return asset tag if already created.
+    if ( pAssetTag != NULL )
+        return pAssetTag;
+
+    // Fetch tag name.
+    StringTableEntry tagName = fetchTagName( pTagName );
+
+    // Generate the asset tag.
+    pAssetTag = new AssetTag( tagName );
+
+    // Add the tag.
+    mTagNameDatabase.insert( tagName, pAssetTag );
+
+    return pAssetTag;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::renameTag( const char* pOldTagName, const char* pNewTagName )
+{
+    // Sanity!
+    AssertFatal( pOldTagName != NULL, "Cannot use a NULL tag name." );
+    AssertFatal( pNewTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find old asset tags.
+    AssetTag* pOldAssetTag = findAssetTag( pOldTagName );
+
+    // Did we find the asset tag?
+    if ( pOldAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest: Cannot rename tag '%s' as it does not exist.", pOldTagName );
+        return false;
+    }
+
+    // Are the old and new tags the same?
+    if ( pOldAssetTag->mTagName == fetchTagName( pNewTagName ) )
+    {
+        // Yes, so warn.
+        Con::warnf( "AssetTagsManifest: Cannot rename tag '%s' to tag '%s' as they are the same.", pOldTagName, pNewTagName );
+        return false;
+    }
+
+    // Create new tag.
+    AssetTag* pNewAssetTag = const_cast<AssetTag*>( createTag( pNewTagName ) );
+
+    // Transfer asset tags.
+    for ( Vector<typeAssetId>::iterator assetIdItr = pOldAssetTag->mAssets.begin(); assetIdItr != pOldAssetTag->mAssets.end(); ++assetIdItr )
+    {
+        pNewAssetTag->mAssets.push_back( *assetIdItr );
+    }
+
+    // Delete old tag.
+    deleteTag( pOldTagName );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::deleteTag( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Did we find the asset tag?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest: Cannot delete tag '%s' as it does not exist.", pTagName );
+        return false;
+    }
+
+    // Remove the tag.
+    mTagNameDatabase.erase( pAssetTag->mTagName );
+
+    // Remove the asset tags.
+    for ( Vector<typeAssetId>::iterator assetIdItr = pAssetTag->mAssets.begin(); assetIdItr != pAssetTag->mAssets.end(); ++assetIdItr )
+    {
+        // Find asset Id tag.
+        typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find( *assetIdItr );
+
+        // Iterate asset Id tags.
+        while( assetItr != mAssetToTagDatabase.end() && assetItr->key == *assetIdItr )
+        {
+            // Is this the asset tag?
+            if ( assetItr->value == pAssetTag )
+            {
+                // Yes, so erase it.
+                mAssetToTagDatabase.erase( assetItr );
+                break;
+            }
+
+            // Next entry.
+            assetItr++;
+        }
+    }
+
+    // Delete the asset tag.
+    delete pAssetTag;
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::isTag( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Check whether tag exists or not.
+    return findAssetTag( pTagName ) != NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetTagsManifest::getTag( const U32 tagIndex )
+{
+    // Finish if invalid tag count.
+    AssertFatal( tagIndex < getTagCount(), "Tag index is out of bounds." );
+
+    // Fetch tag iterator.
+    typeTagNameHash::iterator tagItr = mTagNameDatabase.begin();
+
+    // Find asset tag by index.
+    // NOTE: Unfortunately this is slow as it's not the natural access method.
+    for( U32 index = 0; index  < tagIndex; ++index, ++tagItr ) {};
+
+    // Return tag name.
+    return tagItr->value->mTagName;
+}
+
+//-----------------------------------------------------------------------------
+
+U32 AssetTagsManifest::getAssetTagCount( const char* pAssetId )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    return (U32)mAssetToTagDatabase.count( assetId );
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetTagsManifest::getAssetTag( const char* pAssetId, const U32 tagIndex )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Sanity!
+    AssertFatal( tagIndex < (U32)mAssetToTagDatabase.count( assetId ), "Asset tag index is out of bounds." );
+
+    // Find asset tag.
+    typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find( assetId );
+
+    // Find asset tag by index.
+    // NOTE: Unfortunately this is slow as it's not the natural access method.
+    for( U32 index = 0; index  < tagIndex; ++index, ++assetItr ) {};
+
+    // Return tag name.
+    return assetItr->value->mTagName;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::tag( const char* pAssetId, const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Does the tag exist?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot tag asset Id '%s' with tag name '%s' as tag name does not exist.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Is the asset Id valid?
+    if ( !AssetDatabase.isDeclaredAsset( pAssetId ) )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Ignoring asset Id '%s' mapped to tag name '%s' as it is not a declared asset Id.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Fetch asset Id.
+    typeAssetId assetId = StringTable->insert( pAssetId );
+
+    // Find asset Id tag.
+    typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find(assetId);
+
+    // Iterate asset Id tags.
+    while( assetItr != mAssetToTagDatabase.end() && assetItr->key == assetId )
+    {
+        // Is the asset already tagged appropriately?
+        if ( assetItr->value == pAssetTag )
+            return true;
+
+        // Next entry.
+        assetItr++;
+    }
+
+    // No, so add tag.
+    mAssetToTagDatabase.insertEqual( assetId, pAssetTag );    
+
+    // Add to asset tag.
+    pAssetTag->mAssets.push_back( assetId );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::untag( const char* pAssetId, const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Does the tag exist?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot untag asset Id '%s' from tag name '%s' as tag name does not exist.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Fetch asset Id.
+    typeAssetId assetId = StringTable->insert( pAssetId );
+
+    // Is the asset tagged?
+    if ( !pAssetTag->containsAsset( assetId ) )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot untag asset Id '%s' from tag name '%s' as the asset is not tagged with the tag name.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Remove asset from assert tag.
+    pAssetTag->removeAsset( assetId );
+
+    // Find asset Id tag.
+    typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find(assetId);
+
+    // Iterate asset Id tags.
+    while( assetItr != mAssetToTagDatabase.end() && assetItr->key == assetId )
+    {
+        // Is this the asset tag?
+        if ( assetItr->value == pAssetTag )
+        {
+            // Yes, so remove it.
+            mAssetToTagDatabase.erase( assetItr );
+            break;
+        }
+
+        // Next entry.
+        assetItr++;
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::hasTag( const char* pAssetId, const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Does the tag exist?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot check if asset Id '%s' has tag name '%s' as tag name does not exist.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Return whether asset Id is tagged.
+    return pAssetTag->containsAsset( StringTable->insert( pAssetId ) );
+}

+ 148 - 0
Engine/source/assets/assetTagsManifest.h

@@ -0,0 +1,148 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_TAGS_MANIFEST_H_
+#define _ASSET_TAGS_MANIFEST_H_
+
+#ifndef _SIMBASE_H_
+#include "console/simBase.h"
+#endif
+
+#ifndef _TDICTIONARY_H_
+#include "core/util/tDictionary.h"
+#endif
+
+#ifndef _TVECTOR_H_
+#include "core/util/tvector.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "core/strings/stringUnit.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+#define ASSETTAGS_TAGS_NODE_NAME                "Tags"
+#define ASSETTAGS_TAGS_TYPE_NAME                "Tag"
+#define ASSETTAGS_TAGS_NAME_FIELD               "Name"
+
+#define ASSETTAGS_ASSETS_NODE_NAME              "Assets"
+#define ASSETTAGS_ASSETS_TYPE_NAME              "Tag"
+#define ASSETTAGS_ASSETS_ASSETID_FIELD          "AssetId"
+#define ASSETTAGS_ASSETS_TAG_FIELD              "Name"
+
+//-----------------------------------------------------------------------------
+
+class AssetManager;
+
+//-----------------------------------------------------------------------------
+
+class AssetTagsManifest : public SimObject
+{
+    friend class AssetManager;
+
+private:
+    typedef SimObject Parent;
+    typedef StringTableEntry typeAssetId;
+    typedef StringTableEntry typeAssetTagName;
+
+public:
+    /// Asset location.
+    class AssetTag
+    {
+    public:
+        AssetTag( StringTableEntry tagName )
+        {
+            // Sanity!
+            AssertFatal( tagName != NULL, "Cannot use a NULL tag name." );
+
+            // Case sensitive tag name.
+            mTagName = tagName;
+        }
+
+        bool containsAsset( typeAssetId assetId )
+        {
+            for ( Vector<typeAssetId>::iterator assetIdItr = mAssets.begin(); assetIdItr != mAssets.end(); ++assetIdItr )
+            {
+                if ( *assetIdItr == assetId )
+                    return true;
+            }
+
+            return false;
+        }
+
+        void removeAsset( typeAssetId assetId )
+        {
+            for ( Vector<typeAssetId>::iterator assetIdItr = mAssets.begin(); assetIdItr != mAssets.end(); ++assetIdItr )
+            {
+                if ( *assetIdItr == assetId )
+                {
+                    mAssets.erase( assetIdItr );
+                    return;
+                }
+            }
+        }
+
+        typeAssetTagName mTagName;
+        Vector<typeAssetId> mAssets;
+    };
+
+    /// Asset/Tag database.
+    typedef HashMap<typeAssetTagName, AssetTag*> typeTagNameHash;
+    typedef HashTable<typeAssetId, AssetTag*> typeAssetToTagHash;
+
+private:
+    typeTagNameHash mTagNameDatabase;
+    typeAssetToTagHash mAssetToTagDatabase;
+
+private:
+    StringTableEntry fetchTagName( const char* pTagName );
+    AssetTag* findAssetTag( const char* pTagName );
+    void renameAssetId( const char* pAssetIdFrom, const char* pAssetIdTo );
+
+protected:
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
+
+public:
+    AssetTagsManifest();
+    virtual ~AssetTagsManifest();
+
+    /// Tagging.
+    const AssetTag* createTag( const char* pTagName );
+    bool renameTag( const char* pOldTagName, const char* pNewTagName );
+    bool deleteTag( const char* pTagName );
+    bool isTag( const char* pTagName );
+    inline U32 getTagCount( void ) const { return (U32)mTagNameDatabase.size(); }
+    StringTableEntry getTag( const U32 tagIndex );
+    U32 getAssetTagCount( const char* pAssetId );
+    StringTableEntry getAssetTag( const char* pAssetId, const U32 tagIndex );
+    bool tag( const char* pAssetId, const char* pTagName );
+    bool untag( const char* pAssetId, const char* pTagName );
+    bool hasTag( const char* pAssetId, const char* pTagName );
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( AssetTagsManifest );
+};
+
+#endif // _ASSET_TAGS_MANIFEST_H_
+

+ 151 - 0
Engine/source/assets/assetTagsManifest_ScriptBinding.h

@@ -0,0 +1,151 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#include "console/engineAPI.h"
+#include "assetTagsManifest.h"
+
+DefineEngineMethod(AssetTagsManifest, createTag, void, (const char* tagName), (""),
+   "Creates an asset tag.\n"
+   "@param tagName The tag name to create.\n"
+   "@return No return value.\n")
+{
+   object->createTag(tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, renameTag, bool, (const char* oldTagName, const char* newTagName),,
+   "Renames an existing asset tag.\n"
+   "@param tagName The tag name to rename.\n"
+   "@param newTagName The new tag name to assign.\n"
+   "@return Whether the asset tag was renamed or not.\n")
+{
+   return object->renameTag(oldTagName, newTagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, deleteTag, bool, (const char* tagName),,
+   "Deletes an asset tag.\n"
+   "@param tagName The tag name to delete.\n"
+   "@return Whether the asset tag was deleted or not.\n")
+{
+   return object->deleteTag(tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, isTag, bool, (const char* tagName),,
+   "Checks whether the specified asset tag exists or not.\n"
+   "@param tagName The tag name to check.\n"
+   "@return Whether the specified asset tag exists or not.\n")
+{
+   return object->isTag(tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getTagCount, S32, (),,
+   "Gets the total asset tag count.\n"
+   "@return The total asset tag count.\n")
+{
+    return object->getTagCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getTag, const char*, (S32 tagIndex),,
+   "Gets the asset tag at the specified index.\n"
+   "@param tagIndex The asset tag index.This must be 0 to the asset tag count less one.\n"
+   "@return The asset tag at the specified index or NULL if invalid.\n")
+{
+    // Is the tag index out-of-bounds?
+    if ( tagIndex >= object->getTagCount() )
+    {
+        // Yes, so warn.
+        Con::warnf( "AssetTagsManifest: Asset tag index '%d' is out of bounds.  Asset tag count is '%d'", tagIndex, object->getTagCount() );
+        return StringTable->EmptyString();
+    }
+
+    return object->getTag( tagIndex );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getAssetTagCount, S32, (const char* assetId),,
+   "Gets the asset tag count on the specified asset Id.\n"
+   "@param assetId The asset Id to count tags on.\n"
+   "@return The asset tag count on the specified asset Id.\n")
+{
+   return object->getAssetTagCount(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getAssetTag, const char*, (const char* assetId, S32 tagIndex), ,
+   "Gets the asset tag on the specified asset Id at the specified index.\n"
+   "@param assetId The asset Id to count tags on.\n"
+   "@param tagIndex The asset tag index.This must be 0 to the asset tag count less one.\n"
+   "@return The asset tag on the specified asset Id at the specified index or NULL if invalid.\n")
+{
+   // Is the tag index out-of-bounds?
+   if (tagIndex >= object->getAssetTagCount(assetId))
+   {
+      // Yes, so warn.
+      Con::warnf("AssetTagsManifest: Asset tag index '%d' is out of bounds.  Asset tag count is '%d'", tagIndex, object->getAssetTagCount(assetId));
+      return StringTable->EmptyString();
+   }
+
+   return object->getAssetTag(assetId, tagIndex);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, tag, bool, (const char* assetId, const char* tagName),,
+   "Tags the asset Id with the specified asset tag.\n"
+   "@param assetId The asset Id to tag.\n"
+   "@param tagName The tag name to assign.\n"
+   "@return Whether the tag operation was successful or not.\n")
+{
+   return object->tag(assetId, tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, untag, bool, (const char* assetId, const char* tagName),,
+   "Un-tags the asset Id from the specified asset tag.\n"
+   "@param assetId The asset Id to un - tag.\n"
+   "@param tagName The tag name to un - assign.\n"
+   "@return Whether the un - tag operation was successful or not.\n")
+{
+   return object->untag(assetId, tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, hasTag, bool, (const char* assetId, const char* tagName), ,
+   "Checks whether the asset Id is tagged with the specified asset tag.\n"
+   "@param assetId The asset Id to check.\n"
+   "@param tagName The tag name to check.\n"
+   "@return Whether the asset Id is tagged with the specified asset tag or not.\n")
+{
+   return object->hasTag(assetId, tagName);
+}

+ 12 - 0
Engine/source/assets/core.h

@@ -0,0 +1,12 @@
+#ifndef _ASSET_CORE_H_
+#define _ASSET_CORE_H_
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assetDefinition.h"
+#endif
+
+#endif

+ 45 - 0
Engine/source/assets/declaredAssets.cpp

@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _DECLARED_ASSETS_H_
+#include "assets/declaredAssets.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( DeclaredAssets );
+
+//-----------------------------------------------------------------------------
+
+void DeclaredAssets::initPersistFields()
+{
+    // Call Parent.
+    Parent::initPersistFields();
+        
+    addField("Path", TypeString, Offset(mPath, DeclaredAssets), "" );
+    addField("Extension", TypeString, Offset(mExtension, DeclaredAssets), "" );
+    addField("Recurse", TypeBool, Offset(mRecurse, DeclaredAssets), "" );
+}

+ 73 - 0
Engine/source/assets/declaredAssets.h

@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _DECLARED_ASSETS_H_
+#define _DECLARED_ASSETS_H_
+
+#ifndef _SIM_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _SIMOBJECT_H_
+#include "console/simObject.h"
+#endif
+
+#ifndef _CONSOLEOBJECT_H_
+#include "console/consoleObject.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class DeclaredAssets : public SimObject
+{
+    friend class AssetManager;
+
+private:
+    typedef SimObject Parent;
+
+    StringTableEntry    mPath;
+    StringTableEntry    mExtension;
+    bool                mRecurse;
+
+public:
+    DeclaredAssets() :
+        mPath( StringTable->EmptyString() ),
+        mExtension(StringTable->EmptyString()),
+        mRecurse( false )
+        {}
+    virtual ~DeclaredAssets() {}
+
+    static void initPersistFields();
+
+    inline void setPath( const char* pPath )            { mPath = StringTable->insert( pPath ); }
+    inline StringTableEntry getPath( void ) const       { return mPath; }
+    inline void setExtension( const char* pPath )       { mExtension = StringTable->insert( pPath ); }
+    inline StringTableEntry getExtension( void ) const  { return mExtension; }
+    inline void setRecurse( const bool recurse )        { mRecurse = recurse; }
+    inline bool getRecurse( void ) const                { return mRecurse; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( DeclaredAssets );
+};
+
+#endif // _DECLARED_ASSETS_H_
+

+ 45 - 0
Engine/source/assets/referencedAssets.cpp

@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _REFERENCED_ASSETS_H_
+#include "assets/referencedAssets.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( ReferencedAssets );
+
+//-----------------------------------------------------------------------------
+
+void ReferencedAssets::initPersistFields()
+{
+    // Call Parent.
+    Parent::initPersistFields();
+        
+    addField("Path", TypeString, Offset(mPath, ReferencedAssets), "" );
+    addField("Extension", TypeString, Offset(mExtension, ReferencedAssets), "" );
+    addField("Recurse", TypeBool, Offset(mRecurse, ReferencedAssets), "" );
+}

+ 73 - 0
Engine/source/assets/referencedAssets.h

@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _REFERENCED_ASSETS_H_
+#define _REFERENCED_ASSETS_H_
+
+#ifndef _SIM_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _SIMOBJECT_H_
+#include "console/simObject.h"
+#endif
+
+#ifndef _CONSOLEOBJECT_H_
+#include "console/consoleObject.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class ReferencedAssets : public SimObject
+{
+    friend class AssetManager;
+
+private:
+    typedef SimObject Parent;
+
+    StringTableEntry    mPath;
+    StringTableEntry    mExtension;
+    bool                mRecurse;
+
+public:
+    ReferencedAssets() :
+        mPath( StringTable->EmptyString() ),
+        mExtension(StringTable->EmptyString()),
+        mRecurse( false )
+        {}
+    virtual ~ReferencedAssets() {}
+
+    static void initPersistFields();
+
+    inline void setPath( const char* pPath )            { mPath = StringTable->insert( pPath ); }
+    inline StringTableEntry getPath( void ) const       { return mPath; }
+    inline void setExtension( const char* pPath )       { mExtension = StringTable->insert( pPath ); }
+    inline StringTableEntry getExtension( void ) const  { return mExtension; }
+    inline void setRecurse( const bool recurse )        { mRecurse = recurse; }
+    inline bool getRecurse( void ) const                { return mRecurse; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( ReferencedAssets );
+};
+
+#endif // _REFERENCED_ASSETS_H_
+

+ 132 - 0
Engine/source/assets/tamlAssetDeclaredUpdateVisitor.h

@@ -0,0 +1,132 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_
+#define _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence\/taml/tamlParser.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetDeclaredUpdateVisitor : public TamlVisitor
+{
+private:    
+    StringTableEntry mAssetIdFrom;
+    StringTableEntry mAssetIdTo;
+    StringTableEntry mAssetNameFrom;
+    StringTableEntry mAssetNameTo;
+
+public:
+    TamlAssetDeclaredUpdateVisitor() {}
+    virtual ~TamlAssetDeclaredUpdateVisitor() {}
+
+    void setAssetIdFrom( const char* pAssetIdFrom )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdFrom != NULL, "Asset Id from cannot be NULL." );
+
+        // Reset asset Id.
+        mAssetIdFrom = StringTable->EmptyString();
+        mAssetNameFrom = StringTable->EmptyString();
+
+        // Is asset Id the correct format?
+        if ( StringUnit::getUnitCount( pAssetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
+        {
+            // No, so warn.
+            Con::warnf( "TamlAssetDeclaredUpdateVisitor::setAssetIdFrom() - Cannot use asset Id '%s' as it is not the correct format.", pAssetIdFrom );
+            return;
+        }
+
+        // Set asset Id.
+        mAssetIdFrom = StringTable->insert( pAssetIdFrom );
+        mAssetNameFrom = StringTable->insert( StringUnit::getUnit( pAssetIdFrom, 1, ASSET_SCOPE_TOKEN ) );
+    }
+    StringTableEntry getAssetIdFrom( void ) const { return mAssetIdFrom; }
+
+    void setAssetIdTo( const char* pAssetIdTo )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdTo != NULL, "Asset Id to cannot be NULL." );
+
+        // Reset asset Id.
+        mAssetIdTo = StringTable->EmptyString();
+        mAssetNameTo = StringTable->EmptyString();
+
+        // Is asset Id the correct format?
+        if ( StringUnit::getUnitCount( pAssetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
+        {
+            // No, so warn.
+            Con::warnf( "TamlAssetDeclaredUpdateVisitor::setAssetIdTo() - Cannot use asset Id '%s' as it is not the correct format.", pAssetIdTo );
+            return;
+        }
+
+        // Set asset Id.
+        mAssetIdTo = StringTable->insert( pAssetIdTo );
+        mAssetNameTo = StringTable->insert( StringUnit::getUnit( pAssetIdTo, 1, ASSET_SCOPE_TOKEN ) );
+    }
+    const char* getAssetIdTo( void ) const { return mAssetIdTo; }
+
+    virtual bool wantsPropertyChanges( void ) { return true; }
+    virtual bool wantsRootOnly( void ) { return true; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetDeclaredUpdateVisitor_Visit);
+
+        // Finish if not the asset name field.
+        if ( propertyState.getPropertyName() != assetNameField )
+            return true;
+
+        // Is this the asset Id we're looking for?
+        if ( dStricmp( propertyState.getPropertyValue(), mAssetNameFrom ) != 0 )
+        {
+            // No, so warn.
+            Con::warnf("Cannot rename asset Name '%s' to asset Name '%s' as the declared asset Name was %s",
+                mAssetNameFrom, mAssetNameTo, propertyState.getPropertyValue() );
+
+            // Stop processing!
+            return false;
+        }
+
+        // Assign new value.
+        propertyState.updatePropertyValue( mAssetNameTo );
+
+        // Stop processing!
+        return false;
+    }
+};
+
+#endif // _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_

+ 189 - 0
Engine/source/assets/tamlAssetDeclaredVisitor.h

@@ -0,0 +1,189 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_DECLARED_VISITOR_H_
+#define _TAML_ASSET_DECLARED_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence\/taml/tamlParser.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assetDefinition.h"
+#endif
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetDeclaredVisitor : public TamlVisitor
+{
+public:
+    typedef StringTableEntry typeAssetId;
+    typedef Vector<typeAssetId> typeAssetIdVector;
+    typedef Vector<StringTableEntry> typeLooseFileVector;
+
+private:
+    AssetDefinition         mAssetDefinition;
+    typeAssetIdVector       mAssetDependencies;
+    typeLooseFileVector     mAssetLooseFiles;
+
+public:
+    TamlAssetDeclaredVisitor() { mAssetDefinition.reset(); }
+    virtual ~TamlAssetDeclaredVisitor() {}
+
+
+    inline AssetDefinition& getAssetDefinition( void ) { return mAssetDefinition; }
+    inline typeAssetIdVector& getAssetDependencies( void ) { return mAssetDependencies; }
+    inline typeLooseFileVector& getAssetLooseFiles( void ) { return mAssetLooseFiles; }
+
+    void clear( void ) { mAssetDefinition.reset(); mAssetDependencies.clear(); mAssetLooseFiles.clear(); }
+
+    virtual bool wantsPropertyChanges( void ) { return false; }
+    virtual bool wantsRootOnly( void ) { return false; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {    
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetDeclaredVisitor_Visit);
+
+        // Fetch property name and value.
+        StringTableEntry propertyName = propertyState.getPropertyName();
+        const char* pPropertyValue = propertyState.getPropertyValue();
+
+        // Is this the root object?
+        if ( propertyState.isRootObject() )
+        {
+            // Yes, so is the asset type set yet?
+            if ( mAssetDefinition.mAssetType == StringTable->EmptyString() )
+            {
+                // No, set set asset type and base file-path.
+                mAssetDefinition.mAssetType = propertyState.getObjectName();
+                mAssetDefinition.mAssetBaseFilePath = parser.getParsingFilename();
+            }
+
+            // Asset name?
+            if ( propertyName == assetNameField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetName = StringTable->insert( pPropertyValue );
+                return true;
+            }
+            // Asset description?
+            else if ( propertyName == assetDescriptionField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetDescription = StringTable->insert( pPropertyValue );
+                return true;
+            }
+            // Asset description?
+            else if ( propertyName == assetCategoryField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetCategory = StringTable->insert( pPropertyValue );
+                return true;
+            }
+            // Asset auto-unload?
+            else if ( propertyName == assetAutoUnloadField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetAutoUnload = dAtob( pPropertyValue );
+                return true;
+            }
+            // Asset internal?
+            else if ( propertyName == assetInternalField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetInternal = dAtob( pPropertyValue );
+                return true;
+            }
+        }
+
+        // Fetch property word count.
+        const U32 propertyWordCount = StringUnit::getUnitCount( pPropertyValue, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if there's not two words.
+        if ( propertyWordCount != 2 )
+            return true;
+
+        // Fetch the asset signature.
+        StringTableEntry assetSignature = StringTable->insert( StringUnit::getUnit( pPropertyValue, 0, ASSET_ASSIGNMENT_TOKEN ) );
+
+        // Is this an asset Id signature?
+        if ( assetSignature == assetLooseIdSignature )
+        {
+            // Yes, so get asset Id.
+            typeAssetId assetId = StringTable->insert( StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN ) );
+
+            // Finish if the dependency is itself!
+            if ( mAssetDefinition.mAssetId == assetId )
+                return true;
+
+            // Iterate existing dependencies.
+            for( typeAssetIdVector::iterator dependencyItr = mAssetDependencies.begin(); dependencyItr != mAssetDependencies.end(); ++dependencyItr )
+            {
+                // Finish if asset Id is already a dependency.
+                if ( *dependencyItr == assetId )
+                    return true;
+            }
+
+            // Insert asset reference.
+            mAssetDependencies.push_back( assetId );
+        }
+        // Is this a loose-file signature?
+        else if ( assetSignature == assetLooseFileSignature )
+        {
+            // Yes, so get loose-file reference.
+            const char* pAssetLooseFile = StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN );
+
+            // Fetch asset path only.
+            char assetBasePathBuffer[1024];
+            dSprintf( assetBasePathBuffer, sizeof(assetBasePathBuffer), "%s", mAssetDefinition.mAssetBaseFilePath );
+            char* pFinalSlash = dStrrchr( assetBasePathBuffer, '/' );
+            if ( pFinalSlash != NULL ) *pFinalSlash = 0;
+
+            // Expand the path in the usual way.
+            char assetFilePathBuffer[1024];
+            Con::expandPath( assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetLooseFile, assetBasePathBuffer );
+
+            // Insert asset loose-file.
+            mAssetLooseFiles.push_back( StringTable->insert( assetFilePathBuffer ) );
+        }
+
+        return true;
+    }
+};
+
+#endif // _TAML_ASSET_DECLARED_VISITOR_H_

+ 127 - 0
Engine/source/assets/tamlAssetReferencedUpdateVisitor.h

@@ -0,0 +1,127 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_
+#define _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence\/taml/tamlParser.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+#ifndef _STRINGTABLE_H_
+#include "string/stringTable.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetReferencedUpdateVisitor : public TamlVisitor
+{
+private:    
+    StringTableEntry mAssetIdFrom;
+    StringTableEntry mAssetIdTo;
+
+public:
+    TamlAssetReferencedUpdateVisitor() {}
+    virtual ~TamlAssetReferencedUpdateVisitor() {}
+
+    void setAssetIdFrom( const char* pAssetIdFrom )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdFrom != NULL, "Asset Id from cannot be NULL." );
+
+        mAssetIdFrom = StringTable->insert( pAssetIdFrom );
+    }
+    StringTableEntry getAssetIdFrom( void ) const { return mAssetIdFrom; }
+
+    void setAssetIdTo( const char* pAssetIdTo )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdTo != NULL, "Asset Id to cannot be NULL." );
+
+        mAssetIdTo = StringTable->insert( pAssetIdTo );
+    }
+    const char* getAssetIdTo( void ) const { return mAssetIdTo; }
+
+    virtual bool wantsPropertyChanges( void ) { return true; }
+    virtual bool wantsRootOnly( void ) { return false; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetReferencedUpdateVisitor_Visit);
+
+        // Fetch the property value.
+        const char* pPropertyValue = propertyState.getPropertyValue();
+
+        // Fetch property value word count.
+        const U32 valueWordCount = StringUnit::getUnitCount( pPropertyValue, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if not two words.
+        if ( valueWordCount != 2 )
+            return true;
+
+        // Finish if this is not an asset signature.
+        if ( dStricmp( StringUnit::getUnit( pPropertyValue, 0, ASSET_ASSIGNMENT_TOKEN), assetLooseIdSignature ) != 0 )
+            return true;
+
+        // Get the asset value.
+        const char* pAssetValue = StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if not the asset Id we're looking for.
+        if ( dStricmp( pAssetValue, mAssetIdFrom ) != 0 )
+            return true;
+
+        // Is the target asset empty?
+        if ( mAssetIdTo == StringTable->EmptyString() )
+        {
+            // Yes, so update the property as empty.
+           propertyState.updatePropertyValue(StringTable->EmptyString());
+            return true;
+        }
+
+        // Format asset.
+        char assetBuffer[1024];
+        dSprintf( assetBuffer, sizeof(assetBuffer), "%s%s%s", assetLooseIdSignature, ASSET_ASSIGNMENT_TOKEN, mAssetIdTo );
+
+        // Assign new value.
+        propertyState.updatePropertyValue( assetBuffer );
+
+        return true;
+    }
+};
+
+#endif // _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_

+ 96 - 0
Engine/source/assets/tamlAssetReferencedVisitor.h

@@ -0,0 +1,96 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_REFERENCED_VISITOR_H_
+#define _TAML_ASSET_REFERENCED_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence/taml/tamlParser.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetReferencedVisitor : public TamlVisitor
+{
+public:
+    typedef StringTableEntry typeAssetId;
+    typedef HashMap<typeAssetId, StringTableEntry> typeAssetReferencedHash;
+
+private:
+    typeAssetReferencedHash mAssetReferenced;
+
+public:
+    TamlAssetReferencedVisitor() {}
+    virtual ~TamlAssetReferencedVisitor() {}
+
+    const typeAssetReferencedHash& getAssetReferencedMap( void ) const { return mAssetReferenced; }
+
+    void clear( void ) { mAssetReferenced.clear(); }
+
+    virtual bool wantsPropertyChanges( void ) { return false; }
+    virtual bool wantsRootOnly( void ) { return false; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {    
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetReferencedVisitor_Visit);
+
+        // Fetch property value.
+        const char* pPropertyValue = propertyState.getPropertyValue();
+
+        // Fetch property word count.
+        const U32 propertyWordCount = StringUnit::getUnitCount( pPropertyValue, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if there's not two words.
+        if ( propertyWordCount != 2 )
+            return true;
+
+        // Finish if the first word is not an asset signature.
+        if ( StringTable->insert( StringUnit::getUnit( pPropertyValue, 0, ASSET_ASSIGNMENT_TOKEN ) ) != assetLooseIdSignature )
+            return true;
+
+        // Get asset Id.
+        typeAssetId assetId = StringTable->insert( StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN ) );
+
+        // Finish if we already have this asset Id.
+        if ( mAssetReferenced.contains( assetId ) )
+            return true;
+
+        // Insert asset reference.
+        mAssetReferenced.insert( assetId, StringTable->EmptyString() );
+
+        return true;
+    }
+};
+
+#endif // _TAML_ASSET_REFERENCED_VISITOR_H_

+ 1 - 1
Engine/source/collision/boxConvex.cpp

@@ -76,7 +76,7 @@ Point3F BoxConvex::getVertex(S32 v)
    return p;
 }
 
-inline bool isOnPlane(Point3F p,PlaneF& plane)
+inline bool isOnPlane(const Point3F& p,PlaneF& plane)
 {
    F32 dist = mDot(plane,p) + plane.d;
    return dist < 0.1 && dist > -0.1;

+ 1 - 1
Engine/source/console/arrayObject.cpp

@@ -103,7 +103,7 @@ S32 QSORT_CALLBACK ArrayObject::_keyFunctionCompare( const void* a, const void*
    ArrayObject::Element* ea = ( ArrayObject::Element* )( a );
    ArrayObject::Element* eb = ( ArrayObject::Element* )( b );
    
-   S32 result = dAtoi( Con::executef( (const char*)smCompareFunction, ea->value, eb->key ) );
+   S32 result = dAtoi(Con::executef((const char*)smCompareFunction, ea->key, eb->key));
    S32 res = result < 0 ? -1 : ( result > 0 ? 1 : 0 );
    return ( smDecreasing ? -res : res );
 }

+ 0 - 4
Engine/source/console/astNodes.cpp

@@ -258,7 +258,6 @@ void IfStmtNode::propagateSwitchExpr(ExprNode *left, bool string)
 
 U32 IfStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
 {
-   U32 start = ip;
    U32 endifIp, elseIp;
    addBreakLine(codeStream);
    
@@ -340,7 +339,6 @@ U32 LoopStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
    addBreakLine(codeStream);
    codeStream.pushFixScope(true);
    
-   U32 start = ip;
    if(initExpr)
       ip = initExpr->compile(codeStream, ip, TypeReqNone);
 
@@ -1565,8 +1563,6 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream &codeStream, U32 ip)
    
    CodeBlock::smInFunction = false;
    
-   
-   U32 start = ip;
    codeStream.emit(OP_FUNC_DECL);
    codeStream.emitSTE(fnName);
    codeStream.emitSTE(nameSpace);

+ 12 - 4
Engine/source/console/compiledEval.cpp

@@ -209,6 +209,13 @@ namespace Con
       return ret;
    }
 
+   char* getBoolArg(bool arg)
+   {
+      char *ret = STR.getArgBuffer(32);
+      dSprintf(ret, 32, "%d", arg);
+      return ret;
+   }
+
    char *getStringArg( const char *arg )
    {
       U32 len = dStrlen( arg ) + 1;
@@ -435,7 +442,8 @@ static void setFieldComponent( SimObject* object, StringTableEntry field, const
 
 ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, ConsoleValueRef *argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
 {
-#ifdef TORQUE_DEBUG
+
+#ifdef TORQUE_VALIDATE_STACK
    U32 stackStart = STR.mStartStackSize;
    U32 consoleStackStart = CSTK.mStackPos;
 #endif
@@ -2245,9 +2253,9 @@ execFinished:
 
    decRefCount();
 
-#ifdef TORQUE_DEBUG
-   //AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
-   //AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
+#ifdef TORQUE_VALIDATE_STACK
+   AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
+   AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
 #endif
 
    return returnValue;

+ 1 - 1
Engine/source/console/compiler.h

@@ -310,7 +310,7 @@ protected:
       U8 *data;       ///< Allocated data (size is BlockSize)
       U32 size;       ///< Bytes used in data
       CodeData *next; ///< Next block
-   };
+   } CodeData;
    
    /// @name Emitted code
    /// {

+ 488 - 0
Engine/source/console/console.cpp

@@ -1566,6 +1566,494 @@ void popInstantGroup()
    }
 }
 
+
+typedef HashMap<StringTableEntry, StringTableEntry> typePathExpandoMap;
+static typePathExpandoMap PathExpandos;
+
+//-----------------------------------------------------------------------------
+
+void addPathExpando(const char* pExpandoName, const char* pPath)
+{
+   // Sanity!
+   AssertFatal(pExpandoName != NULL, "Expando name cannot be NULL.");
+   AssertFatal(pPath != NULL, "Expando path cannot be NULL.");
+
+   // Fetch expando name.
+   StringTableEntry expandoName = StringTable->insert(pExpandoName);
+
+   // Fetch the length of the path.
+   S32 pathLength = dStrlen(pPath);
+
+   char pathBuffer[1024];
+
+   // Sanity!
+   if (pathLength == 0 || pathLength >= sizeof(pathBuffer))
+   {
+      Con::warnf("Cannot add path expando '%s' with path '%s' as the path is an invalid length.", pExpandoName, pPath);
+      return;
+   }
+
+   // Strip repeat slashes.
+   if (!Con::stripRepeatSlashes(pathBuffer, pPath, sizeof(pathBuffer)))
+   {
+      Con::warnf("Cannot add path expando '%s' with path '%s' as the path is an invalid length.", pExpandoName, pPath);
+      return;
+   }
+
+   // Fetch new path length.
+   pathLength = dStrlen(pathBuffer);
+
+   // Sanity!
+   if (pathLength == 0)
+   {
+      Con::warnf("Cannot add path expando '%s' with path '%s' as the path is an invalid length.", pExpandoName, pPath);
+      return;
+   }
+
+   // Remove any terminating slash.
+   if (pathBuffer[pathLength - 1] == '/')
+      pathBuffer[pathLength - 1] = 0;
+
+   // Fetch expanded path.
+   StringTableEntry expandedPath = StringTable->insert(pathBuffer);
+
+   // Info.
+#if defined(TORQUE_DEBUG)
+   Con::printf("Adding path expando of '%s' as '%s'.", expandoName, expandedPath);
+#endif
+
+   // Find any existing path expando.
+   typePathExpandoMap::iterator expandoItr = PathExpandos.find(pExpandoName);
+
+   // Does the expando exist?
+   if (expandoItr != PathExpandos.end())
+   {
+      // Yes, so modify the path.
+      expandoItr->value = expandedPath;
+      return;
+   }
+
+   // Insert expando.
+   PathExpandos.insert(expandoName, expandedPath);
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry getPathExpando(const char* pExpandoName)
+{
+   // Sanity!
+   AssertFatal(pExpandoName != NULL, "Expando name cannot be NULL.");
+
+   // Fetch expando name.
+   StringTableEntry expandoName = StringTable->insert(pExpandoName);
+
+   // Find any existing path expando.
+   typePathExpandoMap::iterator expandoItr = PathExpandos.find(expandoName);
+
+   // Does the expando exist?
+   if (expandoItr != PathExpandos.end())
+   {
+      // Yes, so return it.
+      return expandoItr->value;
+   }
+
+   // Not found.
+   return NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+void removePathExpando(const char* pExpandoName)
+{
+   // Sanity!
+   AssertFatal(pExpandoName != NULL, "Expando name cannot be NULL.");
+
+   // Fetch expando name.
+   StringTableEntry expandoName = StringTable->insert(pExpandoName);
+
+   // Find any existing path expando.
+   typePathExpandoMap::iterator expandoItr = PathExpandos.find(expandoName);
+
+   // Does the expando exist?
+   if (expandoItr == PathExpandos.end())
+   {
+      // No, so warn.
+#if defined(TORQUE_DEBUG)
+      Con::warnf("Removing path expando of '%s' but it does not exist.", expandoName);
+#endif
+      return;
+   }
+
+   // Info.
+#if defined(TORQUE_DEBUG)
+   Con::printf("Removing path expando of '%s' as '%s'.", expandoName, expandoItr->value);
+#endif
+   // Remove expando.
+   PathExpandos.erase(expandoItr);
+}
+
+//-----------------------------------------------------------------------------
+
+bool isPathExpando(const char* pExpandoName)
+{
+   // Sanity!
+   AssertFatal(pExpandoName != NULL, "Expando name cannot be NULL.");
+
+   // Fetch expando name.
+   StringTableEntry expandoName = StringTable->insert(pExpandoName);
+
+   return PathExpandos.contains(expandoName);
+}
+
+//-----------------------------------------------------------------------------
+
+U32 getPathExpandoCount(void)
+{
+   return PathExpandos.size();
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry getPathExpandoKey(U32 expandoIndex)
+{
+   // Finish if index is out of range.
+   if (expandoIndex >= PathExpandos.size())
+      return NULL;
+
+   // Find indexed iterator.
+   typePathExpandoMap::iterator expandoItr = PathExpandos.begin();
+   while (expandoIndex > 0) { ++expandoItr; --expandoIndex; }
+
+   return expandoItr->key;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry getPathExpandoValue(U32 expandoIndex)
+{
+   // Finish if index is out of range.
+   if (expandoIndex >= PathExpandos.size())
+      return NULL;
+
+   // Find indexed iterator.
+   typePathExpandoMap::iterator expandoItr = PathExpandos.begin();
+   while (expandoIndex > 0) { ++expandoItr; --expandoIndex; }
+
+   return expandoItr->value;
+}
+
+//-----------------------------------------------------------------------------
+
+bool expandPath(char* pDstPath, U32 size, const char* pSrcPath, const char* pWorkingDirectoryHint, const bool ensureTrailingSlash)
+{
+   char pathBuffer[2048];
+   const char* pSrc = pSrcPath;
+   char* pSlash;
+
+   // Fetch leading character.
+   const char leadingToken = *pSrc;
+
+   // Fetch following token.
+   const char followingToken = leadingToken != 0 ? pSrc[1] : 0;
+
+   // Expando.
+   if (leadingToken == '^')
+   {
+      // Initial prefix search.
+      const char* pPrefixSrc = pSrc + 1;
+      char* pPrefixDst = pathBuffer;
+
+      // Search for end of expando.
+      while (*pPrefixSrc != '/' && *pPrefixSrc != 0)
+      {
+         // Copy prefix character.
+         *pPrefixDst++ = *pPrefixSrc++;
+      }
+
+      // Yes, so terminate the expando string.
+      *pPrefixDst = 0;
+
+      // Fetch the expando path.
+      StringTableEntry expandoPath = getPathExpando(pathBuffer);
+
+      // Does the expando exist?
+      if (expandoPath == NULL)
+      {
+         // No, so error.
+         Con::errorf("expandPath() : Could not find path expando '%s' for path '%s'.", pathBuffer, pSrcPath);
+
+         // Are we ensuring the trailing slash?
+         if (ensureTrailingSlash)
+         {
+            // Yes, so ensure it.
+            Con::ensureTrailingSlash(pDstPath, pSrcPath);
+         }
+         else
+         {
+            // No, so just use the source path.
+            dStrcpy(pDstPath, pSrcPath);
+         }
+
+         return false;
+      }
+
+      // Skip the expando and the following slash.
+      pSrc += dStrlen(pathBuffer) + 1;
+
+      // Format the output path.
+      dSprintf(pathBuffer, sizeof(pathBuffer), "%s/%s", expandoPath, pSrc);
+
+      // Are we ensuring the trailing slash?
+      if (ensureTrailingSlash)
+      {
+         // Yes, so ensure it.
+         Con::ensureTrailingSlash(pathBuffer, pathBuffer);
+      }
+
+      // Strip repeat slashes.
+      Con::stripRepeatSlashes(pDstPath, pathBuffer, size);
+
+      return true;
+   }
+
+   // Script-Relative.
+   if (leadingToken == '.')
+   {
+      // Fetch the code-block file-path.
+      const StringTableEntry codeblockFullPath = CodeBlock::getCurrentCodeBlockFullPath();
+
+      // Do we have a code block full path?
+      if (codeblockFullPath == NULL)
+      {
+         // No, so error.
+         Con::errorf("expandPath() : Could not find relative path from code-block for path '%s'.", pSrcPath);
+
+         // Are we ensuring the trailing slash?
+         if (ensureTrailingSlash)
+         {
+            // Yes, so ensure it.
+            Con::ensureTrailingSlash(pDstPath, pSrcPath);
+         }
+         else
+         {
+            // No, so just use the source path.
+            dStrcpy(pDstPath, pSrcPath);
+         }
+
+         return false;
+      }
+
+      // Yes, so use it as the prefix.
+      dStrncpy(pathBuffer, codeblockFullPath, sizeof(pathBuffer) - 1);
+
+      // Find the final slash in the code-block.
+      pSlash = dStrrchr(pathBuffer, '/');
+
+      // Is this a parent directory token?
+      if (followingToken == '.')
+      {
+         // Yes, so terminate after the slash so we include it.
+         pSlash[1] = 0;
+      }
+      else
+      {
+         // No, it's a current directory token so terminate at the slash so we don't include it.
+         pSlash[0] = 0;
+
+         // Skip the current directory token.
+         pSrc++;
+      }
+
+      // Format the output path.
+      dStrncat(pathBuffer, "/", sizeof(pathBuffer) - 1 - strlen(pathBuffer));
+      dStrncat(pathBuffer, pSrc, sizeof(pathBuffer) - 1 - strlen(pathBuffer));
+
+      // Are we ensuring the trailing slash?
+      if (ensureTrailingSlash)
+      {
+         // Yes, so ensure it.
+         Con::ensureTrailingSlash(pathBuffer, pathBuffer);
+      }
+
+      // Strip repeat slashes.
+      Con::stripRepeatSlashes(pDstPath, pathBuffer, size);
+
+      return true;
+   }
+
+   // All else.
+
+   //Using a special case here because the code below barfs on trying to build a full path for apk reading
+#ifdef TORQUE_OS_ANDROID
+   if (leadingToken == '/' || strstr(pSrcPath, "/") == NULL)
+      Platform::makeFullPathName(pSrcPath, pathBuffer, sizeof(pathBuffer), pWorkingDirectoryHint);
+   else
+      dSprintf(pathBuffer, sizeof(pathBuffer), "/%s", pSrcPath);
+#else
+   Platform::makeFullPathName(pSrcPath, pathBuffer, sizeof(pathBuffer), pWorkingDirectoryHint);
+#endif
+
+   // Are we ensuring the trailing slash?
+   if (ensureTrailingSlash)
+   {
+      // Yes, so ensure it.
+      Con::ensureTrailingSlash(pathBuffer, pathBuffer);
+   }
+
+   // Strip repeat slashes.
+   Con::stripRepeatSlashes(pDstPath, pathBuffer, size);
+
+   return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool isBasePath(const char* SrcPath, const char* pBasePath)
+{
+   char expandBuffer[1024];
+   Con::expandPath(expandBuffer, sizeof(expandBuffer), SrcPath);
+   return dStrnicmp(pBasePath, expandBuffer, dStrlen(pBasePath)) == 0;
+}
+
+//-----------------------------------------------------------------------------
+
+void collapsePath(char* pDstPath, U32 size, const char* pSrcPath, const char* pWorkingDirectoryHint)
+{
+   // Check path against expandos.  If there are multiple matches, choose the
+   // expando that produces the shortest relative path.
+
+   char pathBuffer[2048];
+
+   // Fetch expando count.
+   const U32 expandoCount = getPathExpandoCount();
+
+   // Iterate expandos.
+   U32 expandoRelativePathLength = U32_MAX;
+   for (U32 expandoIndex = 0; expandoIndex < expandoCount; ++expandoIndex)
+   {
+      // Fetch expando value (path).
+      StringTableEntry expandoValue = getPathExpandoValue(expandoIndex);
+
+      // Skip if not the base path.
+      if (!isBasePath(pSrcPath, expandoValue))
+         continue;
+
+      // Fetch path relative to expando path.
+      StringTableEntry relativePath = Platform::makeRelativePathName(pSrcPath, expandoValue);
+
+      // If the relative path is simply a period
+      if (relativePath[0] == '.')
+         relativePath++;
+
+      if (dStrlen(relativePath) > expandoRelativePathLength)
+      {
+         // This expando covers less of the path than any previous one found.
+         // We will keep the previous one.
+         continue;
+      }
+
+      // Keep track of the relative path length
+      expandoRelativePathLength = dStrlen(relativePath);
+
+      // Fetch expando key (name).
+      StringTableEntry expandoName = getPathExpandoKey(expandoIndex);
+
+      // Format against expando.
+      dSprintf(pathBuffer, sizeof(pathBuffer), "^%s/%s", expandoName, relativePath);
+   }
+
+   // Check if we've found a suitable expando
+   if (expandoRelativePathLength != U32_MAX)
+   {
+      // Strip repeat slashes.
+      Con::stripRepeatSlashes(pDstPath, pathBuffer, size);
+
+      return;
+   }
+
+   // Fetch the working directory.
+   StringTableEntry workingDirectory = pWorkingDirectoryHint != NULL ? pWorkingDirectoryHint : Platform::getCurrentDirectory();
+
+   // Fetch path relative to current directory.
+   StringTableEntry relativePath = Platform::makeRelativePathName(pSrcPath, workingDirectory);
+
+   // If the relative path is simply a period
+   if (relativePath[0] == '.'  && relativePath[1] != '.')
+      relativePath++;
+
+   // Format against expando.
+   dSprintf(pathBuffer, sizeof(pathBuffer), "%s/%s", workingDirectory, relativePath);
+
+   // Strip repeat slashes.
+   Con::stripRepeatSlashes(pDstPath, pathBuffer, size);
+}
+
+
+void ensureTrailingSlash(char* pDstPath, const char* pSrcPath)
+{
+   // Copy to target.
+   dStrcpy(pDstPath, pSrcPath);
+
+   // Find trailing character index.
+   S32 trailIndex = dStrlen(pDstPath);
+
+   // Ignore if empty string.
+   if (trailIndex == 0)
+      return;
+
+   // Finish if the trailing slash already exists.
+   if (pDstPath[trailIndex - 1] == '/')
+      return;
+
+   // Add trailing slash.
+   pDstPath[trailIndex++] = '/';
+   pDstPath[trailIndex] = 0;
+}
+
+//-----------------------------------------------------------------------------
+
+bool stripRepeatSlashes(char* pDstPath, const char* pSrcPath, S32 dstSize)
+{
+   // Note original destination.
+   char* pOriginalDst = pDstPath;
+
+   // Reset last source character.
+   char lastSrcChar = 0;
+
+   // Search source...
+   while (dstSize > 0)
+   {
+      // Fetch characters.
+      const char srcChar = *pSrcPath++;
+
+      // Do we have a repeat slash?
+      if (srcChar == '/' && lastSrcChar == '/')
+      {
+         // Yes, so skip it.
+         continue;
+      }
+
+      // No, so copy character.
+      *pDstPath++ = srcChar;
+
+      // Finish if end of source.
+      if (srcChar == 0)
+         return true;
+
+      // Reduce room left in destination.
+      dstSize--;
+
+      // Set last character.
+      lastSrcChar = srcChar;
+   }
+
+   // Terminate the destination string as we ran out of room.
+   *pOriginalDst = 0;
+
+   // Fail!
+   return false;
+}
+
 } // end of Console namespace
 
 #endif

+ 27 - 3
Engine/source/console/console.h

@@ -191,7 +191,7 @@ public:
    
    void cleanup()
    {
-      if (bufferLen > 0)
+      if ((type <= TypeInternalString) && (bufferLen > 0))
       {
          dFree(sval);
          bufferLen = 0;
@@ -201,6 +201,8 @@ public:
       ival = 0;
       fval = 0;
    }
+   ConsoleValue(){ init(); };
+   ~ConsoleValue(){ cleanup(); };
 };
 
 // Proxy class for console variables
@@ -484,6 +486,20 @@ namespace Con
    bool expandToolScriptFilename(char *filename, U32 size, const char *src);
    bool collapseScriptFilename(char *filename, U32 size, const char *src);
 
+   bool expandPath(char* pDstPath, U32 size, const char* pSrcPath, const char* pWorkingDirectoryHint = NULL, const bool ensureTrailingSlash = false);
+   void collapsePath(char* pDstPath, U32 size, const char* pSrcPath, const char* pWorkingDirectoryHint = NULL);
+   bool isBasePath(const char* SrcPath, const char* pBasePath);
+   void ensureTrailingSlash(char* pDstPath, const char* pSrcPath);
+   bool stripRepeatSlashes(char* pDstPath, const char* pSrcPath, S32 dstSize);
+
+   void addPathExpando(const char* pExpandoName, const char* pPath);
+   void removePathExpando(const char* pExpandoName);
+   bool isPathExpando(const char* pExpandoName);
+   StringTableEntry getPathExpando(const char* pExpandoName);
+   U32 getPathExpandoCount(void);
+   StringTableEntry getPathExpandoKey(U32 expandoIndex);
+   StringTableEntry getPathExpandoValue(U32 expandoIndex);
+
    bool isCurrentScriptToolScript();
 
    StringTableEntry getModNameFromPath(const char *path);
@@ -737,6 +753,13 @@ namespace Con
    /// @see Con::errorf()
    void errorf(ConsoleLogEntry::Type type, const char *_format, ...);
 
+   //some additions from t2d
+   /// Prints a separator to the console.
+   inline void printSeparator(void) { printf("--------------------------------------------------------------------------------"); }
+
+   /// Prints a separator to the console.
+   inline void printBlankLine(void) { printf(""); }
+
    /// @}
 
    /// Returns true when called from the main thread, false otherwise
@@ -813,6 +836,7 @@ namespace Con
    char* getArgBuffer(U32 bufferSize);
    char* getFloatArg(F64 arg);
    char* getIntArg  (S32 arg);
+   char* getBoolArg(bool arg);
    char* getStringArg( const char* arg );
    char* getStringArg( const String& arg );
    /// @}
@@ -1098,9 +1122,9 @@ struct ConsoleDocFragment
    static ConsoleDocFragment* smFirst;
    
    ConsoleDocFragment( const char* text, const char* inClass = NULL, const char* definition = NULL )
-      : mText( text ),
-        mClass( inClass ),
+      : mClass( inClass ),
         mDefinition( definition ),
+        mText( text ),
         mNext( smFirst )
    {
       smFirst = this;

+ 7 - 10
Engine/source/console/consoleFunctions.cpp

@@ -37,10 +37,6 @@
 #include "math/mPoint3.h"
 #include "math/mathTypes.h"
 
-#ifdef TORQUE_DEMO_PURCHASE
-#include "gui/core/guiCanvas.h"
-#endif
-
 // This is a temporary hack to get tools using the library to
 // link in this module which contains no other references.
 bool LinkConsoleFunctions = false;
@@ -483,7 +479,7 @@ DefineConsoleFunction( strreplace, const char*, ( const char* source, const char
       if(!scan)
       {
          dStrcpy(ret + dstp, source + scanp);
-         break;
+         return ret;
       }
       U32 len = scan - (source + scanp);
       dStrncpy(ret + dstp, source + scanp, len);
@@ -1681,6 +1677,7 @@ DefineEngineFunction( gotoWebPage, void, ( const char* address ),,
 DefineEngineFunction( displaySplashWindow, bool, (const char* path), ("art/gui/splash.bmp"),
    "Display a startup splash window suitable for showing while the engine still starts up.\n\n"
    "@note This is currently only implemented on Windows.\n\n"
+   "@param path	relative path to splash screen image to display.\n"
    "@return True if the splash window could be successfully initialized.\n\n"
    "@ingroup Platform" )
 {
@@ -2352,7 +2349,7 @@ DefineConsoleFunction( isDefined, bool, ( const char* varName, const char* varVa
    "@endtsexample\n\n"
 	"@ingroup Scripting")
 {
-   if(dStrIsEmpty(varName))
+   if(String::isEmpty(varName))
    {
       Con::errorf("isDefined() - did you forget to put quotes around the variable name?");
       return false;
@@ -2428,7 +2425,7 @@ DefineConsoleFunction( isDefined, bool, ( const char* varName, const char* varVa
             {
                if (dStrlen(value) > 0)
                   return true;
-               else if (!dStrIsEmpty(varValue))
+               else if (!String::isEmpty(varValue))
                { 
                   obj->setDataField(valName, 0, varValue); 
                }
@@ -2445,7 +2442,7 @@ DefineConsoleFunction( isDefined, bool, ( const char* varName, const char* varVa
 
          if (ent)
             return true;
-         else if (!dStrIsEmpty(varValue))
+         else if (!String::isEmpty(varValue))
          {
             gEvalState.getCurrentFrame().setVariable(name, varValue);
          }
@@ -2460,7 +2457,7 @@ DefineConsoleFunction( isDefined, bool, ( const char* varName, const char* varVa
 
       if (ent)
          return true;
-      else if (!dStrIsEmpty(varValue))
+      else if (!String::isEmpty(varValue))
       {
          gEvalState.globalVars.setVariable(name, varValue);
       }
@@ -2470,7 +2467,7 @@ DefineConsoleFunction( isDefined, bool, ( const char* varName, const char* varVa
       // Is it an object?
       if (dStrcmp(varName, "0") && dStrcmp(varName, "") && (Sim::findObject(varName) != NULL))
          return true;
-      else if (!dStrIsEmpty(varValue))
+      else if (!String::isEmpty(varValue))
       {
          Con::errorf("%s() - can't assign a value to a variable of the form \"%s\"", __FUNCTION__, varValue);
       }

+ 146 - 43
Engine/source/console/consoleObject.cpp

@@ -55,7 +55,25 @@ bool                               AbstractClassRep::initialized = false;
 
 
 //-----------------------------------------------------------------------------
+AbstractClassRep* AbstractClassRep::findFieldRoot(StringTableEntry fieldName)
+{
+   // Find the field.
+   const Field* pField = findField(fieldName);
+
+   // Finish if not found.
+   if (pField == NULL)
+      return NULL;
 
+   // We're the root if we have no parent.
+   if (getParentClass() == NULL)
+      return this;
+
+   // Find the field root via the parent.
+   AbstractClassRep* pFieldRoot = getParentClass()->findFieldRoot(fieldName);
+
+   // We're the root if the parent does not have it else return the field root.
+   return pFieldRoot == NULL ? this : pFieldRoot;
+}
 
 void AbstractClassRep::init()
 {
@@ -349,6 +367,7 @@ void ConsoleObject::addGroup(const char* in_pGroupname, const char* in_pGroupDoc
    f.validator    = NULL;
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
+   f.writeDataFn = &defaultProtectedWriteFn;
 
    // Add to field list.
    sg_tempFieldList.push_back(f);
@@ -371,6 +390,7 @@ void ConsoleObject::endGroup(const char*  in_pGroupname)
    f.validator    = NULL;
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
+   f.writeDataFn = &defaultProtectedWriteFn;
    f.elementCount = 0;
 
    // Add to field list.
@@ -393,6 +413,7 @@ void ConsoleObject::addArray( const char *arrayName, S32 count )
    f.validator    = NULL;
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
+   f.writeDataFn = &defaultProtectedWriteFn;
 
    // Add to field list.
    sg_tempFieldList.push_back(f);
@@ -412,6 +433,7 @@ void ConsoleObject::endArray( const char *arrayName )
    f.validator    = NULL;
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
+   f.writeDataFn = &defaultProtectedWriteFn;
    f.elementCount = 0;
 
    // Add to field list.
@@ -433,81 +455,159 @@ void ConsoleObject::addField(const char*  in_pFieldname,
       flags );
 }
 
-void ConsoleObject::addProtectedField(const char*  in_pFieldname,
-                       const U32 in_fieldType,
-                       const dsize_t in_fieldOffset,
-                       AbstractClassRep::SetDataNotify in_setDataFn,
-                       AbstractClassRep::GetDataNotify in_getDataFn,
-                       const char* in_pFieldDocs,
-                       U32 flags )
+void ConsoleObject::addField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::WriteDataNotify in_writeDataFn,
+   const char* in_pFieldDocs,
+   U32 flags)
 {
-   addProtectedField(
+   addField(
       in_pFieldname,
       in_fieldType,
       in_fieldOffset,
-      in_setDataFn,
-      in_getDataFn,
+      in_writeDataFn,
       1,
       in_pFieldDocs,
-      flags );
+      flags);
 }
 
+void ConsoleObject::addField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   const U32 in_elementCount,
+   const char* in_pFieldDocs,
+   U32 flags)
+{
+   addField(in_pFieldname,
+      in_fieldType,
+      in_fieldOffset,
+      &defaultProtectedWriteFn,
+      in_elementCount,
+      in_pFieldDocs,
+      flags);
+}
 
 void ConsoleObject::addField(const char*  in_pFieldname,
-                       const U32 in_fieldType,
-                       const dsize_t in_fieldOffset,
-                       const U32 in_elementCount,
-                       const char* in_pFieldDocs,
-                       U32 flags )
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::WriteDataNotify in_writeDataFn,
+   const U32 in_elementCount,
+   const char* in_pFieldDocs,
+   U32 flags)
 {
    AbstractClassRep::Field f;
-   f.pFieldname   = StringTable->insert(in_pFieldname);
+   f.pFieldname = StringTable->insert(in_pFieldname);
 
-   if(in_pFieldDocs)
-      f.pFieldDocs   = in_pFieldDocs;
+   if (in_pFieldDocs)
+      f.pFieldDocs = in_pFieldDocs;
 
-   f.type         = in_fieldType;
-   f.offset       = in_fieldOffset;
+   f.type = in_fieldType;
+   f.offset = in_fieldOffset;
    f.elementCount = in_elementCount;
-   f.validator    = NULL;
-   f.flag         = flags;
+   f.validator = NULL;
+   f.flag = flags;
 
    f.setDataFn = &defaultProtectedSetFn;
-   f.getDataFn    = &defaultProtectedGetFn;
+   f.getDataFn = &defaultProtectedGetFn;
+   f.writeDataFn = in_writeDataFn;
 
-   ConsoleBaseType* conType = ConsoleBaseType::getType( in_fieldType );
-   AssertFatal( conType, "ConsoleObject::addField - invalid console type" );
+   ConsoleBaseType* conType = ConsoleBaseType::getType(in_fieldType);
+   AssertFatal(conType, "ConsoleObject::addField - invalid console type");
    f.table = conType->getEnumTable();
 
    sg_tempFieldList.push_back(f);
 }
 
 void ConsoleObject::addProtectedField(const char*  in_pFieldname,
-                       const U32 in_fieldType,
-                       const dsize_t in_fieldOffset,
-                       AbstractClassRep::SetDataNotify in_setDataFn,
-                       AbstractClassRep::GetDataNotify in_getDataFn,
-                       const U32 in_elementCount,
-                       const char* in_pFieldDocs,
-                       U32 flags )
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::SetDataNotify in_setDataFn,
+   AbstractClassRep::GetDataNotify in_getDataFn,
+   const char* in_pFieldDocs,
+   U32 flags)
+{
+   addProtectedField(
+      in_pFieldname,
+      in_fieldType,
+      in_fieldOffset,
+      in_setDataFn,
+      in_getDataFn,
+      &defaultProtectedWriteFn,
+      1,
+      in_pFieldDocs,
+      flags);
+}
+
+void ConsoleObject::addProtectedField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::SetDataNotify in_setDataFn,
+   AbstractClassRep::GetDataNotify in_getDataFn,
+   AbstractClassRep::WriteDataNotify in_writeDataFn,
+   const char* in_pFieldDocs,
+   U32 flags)
+{
+   addProtectedField(
+      in_pFieldname,
+      in_fieldType,
+      in_fieldOffset,
+      in_setDataFn,
+      in_getDataFn,
+      in_writeDataFn,
+      1,
+      in_pFieldDocs,
+      flags);
+}
+
+void ConsoleObject::addProtectedField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::SetDataNotify in_setDataFn,
+   AbstractClassRep::GetDataNotify in_getDataFn,
+   const U32 in_elementCount,
+   const char* in_pFieldDocs,
+   U32 flags)
+{
+   addProtectedField(
+      in_pFieldname,
+      in_fieldType,
+      in_fieldOffset,
+      in_setDataFn,
+      in_getDataFn,
+      &defaultProtectedWriteFn,
+      in_elementCount,
+      in_pFieldDocs,
+      flags);
+}
+void ConsoleObject::addProtectedField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::SetDataNotify in_setDataFn,
+   AbstractClassRep::GetDataNotify in_getDataFn,
+   AbstractClassRep::WriteDataNotify in_writeDataFn,
+   const U32 in_elementCount,
+   const char* in_pFieldDocs,
+   U32 flags)
 {
    AbstractClassRep::Field f;
-   f.pFieldname   = StringTable->insert(in_pFieldname);
+   f.pFieldname = StringTable->insert(in_pFieldname);
 
-   if(in_pFieldDocs)
-      f.pFieldDocs   = in_pFieldDocs;
+   if (in_pFieldDocs)
+      f.pFieldDocs = in_pFieldDocs;
 
-   f.type         = in_fieldType;
-   f.offset       = in_fieldOffset;
+   f.type = in_fieldType;
+   f.offset = in_fieldOffset;
    f.elementCount = in_elementCount;
-   f.validator    = NULL;
-   f.flag         = flags;
+   f.validator = NULL;
+   f.flag = flags;
 
    f.setDataFn = in_setDataFn;
    f.getDataFn = in_getDataFn;
+   f.writeDataFn = in_writeDataFn;
 
-   ConsoleBaseType* conType = ConsoleBaseType::getType( in_fieldType );
-   AssertFatal( conType, "ConsoleObject::addProtectedField - invalid console type" );
+   ConsoleBaseType* conType = ConsoleBaseType::getType(in_fieldType);
+   AssertFatal(conType, "ConsoleObject::addProtectedField - invalid console type");
    f.table = conType->getEnumTable();
 
    sg_tempFieldList.push_back(f);
@@ -529,6 +629,7 @@ void ConsoleObject::addFieldV(const char*  in_pFieldname,
    f.table        = NULL;
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
+   f.writeDataFn = &defaultProtectedWriteFn;
    f.validator    = v;
    v->fieldIndex  = sg_tempFieldList.size();
 
@@ -546,6 +647,7 @@ void ConsoleObject::addDeprecatedField(const char *fieldName)
    f.validator    = NULL;
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
+   f.writeDataFn = &defaultProtectedWriteFn;
 
    sg_tempFieldList.push_back(f);
 }
@@ -847,12 +949,13 @@ DefineEngineFunction(linkNamespaces, bool, ( String childNSName, String parentNS
    
    Namespace *childNS = Namespace::find(childNSSTE);
    Namespace *parentNS = Namespace::find(parentNSSTE);
-   Namespace *currentParent = childNS->getParent();
    
    if (!childNS)
    {
       return false;
    }
+
+   Namespace *currentParent = childNS->getParent();
    
    // Link to new NS if applicable
    

+ 187 - 59
Engine/source/console/consoleObject.h

@@ -47,7 +47,9 @@
 #ifndef _SIMOBJECTREF_H_
    #include "console/simObjectRef.h"
 #endif
-
+#ifndef TINYXML_INCLUDED
+   #include "tinyxml.h"
+#endif
 
 /// @file
 /// Legacy console object system.
@@ -201,13 +203,16 @@ public:
 
    typedef ConsoleBaseType Parent;
 
+   /// Allows the writing of a custom TAML schema.
+   typedef void(*WriteCustomTamlSchema)(const AbstractClassRep* pClassRep, TiXmlElement* pParentElement);
+
    /// @name 'Tructors
    /// @{
 
    ///
    /// @param conIdPtr Pointer to the static S32 console ID.
    /// @param conTypeName Console type name.
-   AbstractClassRep( S32* conIdPtr, const char* typeName ) 
+   AbstractClassRep( S32* conIdPtr, const char* typeName )
       : Parent( sizeof( void* ), conIdPtr, typeName )
    {
       VECTOR_SET_ASSOCIATION( mFieldList );
@@ -318,10 +323,13 @@ public:
 
    /// Return the namespace that contains the methods of this class.
    Namespace* getNameSpace() const { return mNamespace; }
-   
+
    /// Return the AbstractClassRep of the class that this class is derived from.
    AbstractClassRep* getParentClass() const { return parentClass; }
-   
+
+   virtual AbstractClassRep*    getContainerChildClass(const bool recurse) = 0;
+   virtual WriteCustomTamlSchema getCustomTamlSchema(void) = 0;
+
    /// Return the size of instances of this class in bytes.
    S32 getSizeof() const { return mClassSizeof; }
 
@@ -376,6 +384,8 @@ public:
 
    virtual ConsoleObject*     create      () const = 0;
 
+   AbstractClassRep* findFieldRoot(StringTableEntry fieldName);
+
 protected:
 
    virtual void init();
@@ -386,7 +396,7 @@ protected:
    Namespace *        mNamespace;
 
    /// @}
-   
+
 public:
 
    bool mIsRenderEnabled;
@@ -394,23 +404,23 @@ public:
 
    bool isRenderEnabled() const { return mIsRenderEnabled; }
    bool isSelectionEnabled() const { return mIsSelectionEnabled; }
-      
+
    /// @name Categories
    /// @{
-   
+
 protected:
 
    const char* mCategory;
    const char* mDescription;
-      
+
 public:
 
    /// Return the space separated category path for the class.
    const char* getCategory() const { return mCategory; }
-   
+
    /// Return a short description string suitable for displaying in tooltips.
    const char* getDescription() const { return mDescription; }
-   
+
    /// @}
 
    /// @name Fields
@@ -421,12 +431,15 @@ public:
    typedef bool (*SetDataNotify)( void *obj, const char *array, const char *data );
    typedef const char *(*GetDataNotify)( void *obj, const char *data );
 
+   /// This is a function pointer typedef to support optional writing for fields.
+   typedef bool(*WriteDataNotify)(void* obj, StringTableEntry pFieldName);
+
    /// These are special field type values used to mark
    /// groups and arrays in the field list.
    /// @see Field::type
    /// @see addArray, endArray
-   /// @see addGroup, endGroup   
-   /// @see addGroup, endGroup   
+   /// @see addGroup, endGroup
+   /// @see addGroup, endGroup
    /// @see addDeprecatedField
    enum ACRFieldTypes
    {
@@ -434,35 +447,35 @@ public:
       /// types greater or equal to this one are not
       /// console data types.
       ARCFirstCustomField = 0xFFFFFFFB,
-      
+
       /// Marks the start of a fixed size array of fields.
       /// @see addArray
       StartArrayFieldType = 0xFFFFFFFB,
-      
+
       /// Marks the end of a fixed size array of fields.
       /// @see endArray
       EndArrayFieldType   = 0xFFFFFFFC,
-      
+
       /// Marks the beginning of a group of fields.
       /// @see addGroup
       StartGroupFieldType = 0xFFFFFFFD,
-      
+
       /// Marks the beginning of a group of fields.
       /// @see endGroup
       EndGroupFieldType   = 0xFFFFFFFE,
-      
-      /// Marks a field that is depreciated and no 
+
+      /// Marks a field that is depreciated and no
       /// longer stores a value.
       /// @see addDeprecatedField
       DeprecatedFieldType = 0xFFFFFFFF
    };
-   
+
    enum FieldFlags
    {
       FIELD_HideInInspectors     = BIT( 0 ),    ///< Do not show the field in inspectors.
    };
 
-   struct Field 
+   struct Field
    {
       Field()
          :  pFieldname( NULL ),
@@ -494,6 +507,7 @@ public:
       TypeValidator *validator;     ///< Validator, if any.
       SetDataNotify  setDataFn;     ///< Set data notify Fn
       GetDataNotify  getDataFn;     ///< Get data notify Fn
+      WriteDataNotify writeDataFn;  ///< Function to determine whether data should be written or not.
    };
    typedef Vector<Field> FieldList;
 
@@ -507,10 +521,10 @@ public:
 
    /// @name Console Type Interface
    /// @{
-   
+
    virtual void* getNativeVariable() { return new ( AbstractClassRep* ); } // Any pointer-sized allocation will do.
    virtual void deleteNativeVariable( void* var ) { delete reinterpret_cast< AbstractClassRep** >( var ); }
-   
+
    /// @}
 
    /// @name Abstract Class Database
@@ -556,10 +570,10 @@ template< class T >
 class ConcreteClassRep : public AbstractClassRep
 {
    public:
-   
+
       static EnginePropertyTable _smPropertyTable;
       static EnginePropertyTable& smPropertyTable;
-      
+
       ConcreteClassRep(    const char* name,
                            const char* conTypeName,
                            S32* conTypeIdPtr,
@@ -573,10 +587,10 @@ class ConcreteClassRep : public AbstractClassRep
          mClassName = StringTable->insert( name );
          mCategory = T::__category();
          mTypeInfo = _MAPTYPE< T >();
-         
+
          if( mTypeInfo )
             const_cast< EngineTypeInfo* >( mTypeInfo )->mPropertyTable = &smPropertyTable;
-         
+
          if( &T::__description != parentDesc )
             mDescription = T::__description();
 
@@ -595,6 +609,27 @@ class ConcreteClassRep : public AbstractClassRep
          registerClassRep(this);
       };
 
+      virtual AbstractClassRep* getContainerChildClass(const bool recurse)
+      {
+         // Fetch container children type.
+         AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
+         if (!recurse || pChildren != NULL)
+            return pChildren;
+
+         // Fetch parent type.
+         AbstractClassRep* pParent = T::getParentStaticClassRep();
+         if (pParent == NULL)
+            return NULL;
+
+         // Get parent container children.
+         return pParent->getContainerChildClass(recurse);
+      }
+
+      virtual WriteCustomTamlSchema getCustomTamlSchema(void)
+      {
+         return T::getStaticWriteCustomTamlSchema();
+      }
+
       /// Perform class specific initialization tasks.
       ///
       /// Link namespaces, call initPersistFields() and consoleInit().
@@ -603,7 +638,7 @@ class ConcreteClassRep : public AbstractClassRep
          // Get handle to our parent class, if any, and ourselves (we are our parent's child).
          AbstractClassRep *parent = T::getParentStaticClassRep();
          AbstractClassRep *child  = T::getStaticClassRep();
-                  
+
          // If we got reps, then link those namespaces! (To get proper inheritance.)
          if(parent && child)
             Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
@@ -618,7 +653,7 @@ class ConcreteClassRep : public AbstractClassRep
 
       /// Wrap constructor.
       ConsoleObject* create() const { return new T; }
-      
+
       /// @name Console Type Interface
       /// @{
 
@@ -632,16 +667,16 @@ class ConcreteClassRep : public AbstractClassRep
          else
             Con::errorf( "Cannot set multiple args to a single ConsoleObject*.");
       }
-      
+
       virtual const char* getData( void* dptr, const EnumTable* tbl, BitSet32 flag )
       {
          T** obj = ( T** ) dptr;
          return Con::getReturnBuffer( T::__getObjectId( *obj ) );
       }
-      
+
       virtual const char* getTypeClassName() { return mClassName; }
       virtual const bool isDatablock() { return T::__smIsDatablock; };
-      
+
       /// @}
 };
 
@@ -652,7 +687,7 @@ template< typename T > EnginePropertyTable& ConcreteClassRep< T >::smPropertyTab
 //------------------------------------------------------------------------------
 // Forward declaration of this function so  it can be used in the class
 const char *defaultProtectedGetFn( void *obj, const char *data );
-
+bool defaultProtectedWriteFn(void* obj, StringTableEntry pFieldName);
 
 //=============================================================================
 //    ConsoleObject.
@@ -712,7 +747,7 @@ const char *defaultProtectedGetFn( void *obj, const char *data );
 class ConsoleObject : public EngineObject
 {
    DECLARE_ABSTRACT_CLASS( ConsoleObject, EngineObject );
-   
+
 protected:
 
    /// @deprecated This is disallowed.
@@ -721,7 +756,7 @@ protected:
 public:
 
    ConsoleObject() {}
-   
+
    /// Get a reference to a field by name.
    const AbstractClassRep::Field *findField(StringTableEntry fieldName) const;
 
@@ -730,7 +765,7 @@ public:
 
    /// Set the value of a field.
    bool setField(const char *fieldName, const char *value);
-   
+
 public:
 
    /// @name Object Creation
@@ -760,11 +795,11 @@ public:
    static void endGroup(const char*  in_pGroupname);
 
    /// Marks the start of a fixed size array of fields.
-   /// @see console_autodoc   
+   /// @see console_autodoc
    static void addArray( const char *arrayName, S32 count );
 
    /// Marks the end of an array of fields.
-   /// @see console_autodoc      
+   /// @see console_autodoc
    static void endArray( const char *arrayName );
 
    /// Register a complex field.
@@ -781,6 +816,14 @@ public:
       const char*   in_pFieldDocs   = NULL,
       U32 flags = 0 );
 
+   static void addField(const char*   in_pFieldname,
+      const U32     in_fieldType,
+      const dsize_t in_fieldOffset,
+      AbstractClassRep::WriteDataNotify in_writeDataFn,
+      const U32     in_elementCount = 1,
+      const char*   in_pFieldDocs = NULL,
+      U32 flags = 0);
+
    /// Register a simple field.
    ///
    /// @param  in_pFieldname  Name of the field.
@@ -793,6 +836,13 @@ public:
       const char*   in_pFieldDocs,
       U32 flags = 0 );
 
+   static void addField(const char*   in_pFieldname,
+      const U32     in_fieldType,
+      const dsize_t in_fieldOffset,
+      AbstractClassRep::WriteDataNotify in_writeDataFn,
+      const char*   in_pFieldDocs,
+      U32 flags = 0);
+
    /// Register a validated field.
    ///
    /// A validated field is just like a normal field except that you can't
@@ -821,10 +871,20 @@ public:
       const U32     in_fieldType,
       const dsize_t in_fieldOffset,
       AbstractClassRep::SetDataNotify in_setDataFn,
-      AbstractClassRep::GetDataNotify in_getDataFn,
-      const U32     in_elementCount,
-      const char*   in_pFieldDocs   = NULL,
-      U32 flags = 0 );
+      AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+      AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
+      const U32     in_elementCount = 1,
+      const char*   in_pFieldDocs = NULL,
+      U32 flags = 0);
+
+   static void addProtectedField(const char*  in_pFieldname,
+      const U32 in_fieldType,
+      const dsize_t in_fieldOffset,
+      AbstractClassRep::SetDataNotify in_setDataFn,
+      AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+      const U32 in_elementCount = 1,
+      const char* in_pFieldDocs = NULL,
+      U32 flags = 0);
 
    /// Register a simple protected field.
    ///
@@ -839,8 +899,17 @@ public:
       const dsize_t in_fieldOffset,
       AbstractClassRep::SetDataNotify in_setDataFn,
       AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+      AbstractClassRep::WriteDataNotify in_writeDataFn = &defaultProtectedWriteFn,
       const char*   in_pFieldDocs = NULL,
-      U32 flags = 0 );
+      U32 flags = 0);
+
+   static void addProtectedField(const char*  in_pFieldname,
+      const U32 in_fieldType,
+      const dsize_t in_fieldOffset,
+      AbstractClassRep::SetDataNotify in_setDataFn,
+      AbstractClassRep::GetDataNotify in_getDataFn = &defaultProtectedGetFn,
+      const char* in_pFieldDocs = NULL,
+      U32 flags = 0);
 
    /// Add a deprecated field.
    ///
@@ -855,16 +924,16 @@ public:
    static bool removeField(const char* in_pFieldname);
 
    /// @}
-   
+
    /// @name Logging
    /// @{
-   
+
    /// Overload this in subclasses to change the message formatting.
    /// @param fmt A printf style format string.
    /// @param args A va_list containing the args passed ot a log function.
    /// @note It is suggested that you use String::VToString.
    virtual String _getLogMessage(const char* fmt, va_list args) const;
-   
+
    /// @}
 
 public:
@@ -873,16 +942,16 @@ public:
    /// These functions will try to print out a message along the lines
    /// of "ObjectClass - ObjectName(ObjectId) - formatted message"
    /// @{
-   
+
    /// Logs with Con::printf.
    void logMessage(const char* fmt, ...) const;
-   
+
    /// Logs with Con::warnf.
    void logWarning(const char* fmt, ...) const;
-   
+
    /// Logs with Con::errorf.
    void logError(const char* fmt, ...) const;
-   
+
    /// @}
 
    /// Register dynamic fields in a subclass of ConsoleObject.
@@ -943,16 +1012,16 @@ public:
 
    static const char* __category() { return ""; }
    static const char* __description() { return ""; }
-   
+
    /// Subclasses of ConsoleObjects that are datablocks should redefine this static member variable
    /// and set it to true.
    static const bool __smIsDatablock = false;
-   
+
    /// @name Object IDs and lookup.
    /// For a subclass hierarchy based on ConsoleObject to become functional for use as a console object type,
    /// the hierarchy must implement a naming scheme and indexing function for looking up objects by name.
    /// @{
-   
+
    static ConsoleObject* __findObject( const char* ) { return NULL; }
    static const char* __getObjectId( ConsoleObject* ) { return ""; }
 };
@@ -1045,11 +1114,13 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    static AbstractClassRep* getParentStaticClassRep();   \
    static AbstractClassRep* getStaticClassRep();         \
    static SimObjectRefConsoleBaseType< className > ptrRefType;         \
-   virtual AbstractClassRep* getClassRep() const      
-      
+   static AbstractClassRep::WriteCustomTamlSchema getStaticWriteCustomTamlSchema();         \
+   static AbstractClassRep* getContainerChildStaticClassRep();         \
+   virtual AbstractClassRep* getClassRep() const
+
 #define DECLARE_CATEGORY( string )                      \
    static const char* __category() { return string; }
-   
+
 #define DECLARE_DESCRIPTION( string )                   \
    static const char* __description() { return string; }
 
@@ -1061,6 +1132,44 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }            \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                       \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }  \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+   ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
+
+#define IMPLEMENT_CONOBJECT_CHILDREN( className )                                                           \
+   IMPLEMENT_CLASS( className, NULL )                                                              \
+   END_IMPLEMENT_CLASS;                                                                            \
+   S32 className::_smTypeId;                                                                       \
+   SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" );      \
+   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }            \
+   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                       \
+   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }  \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }                 \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+   ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
+
+#define IMPLEMENT_CONOBJECT_SCHEMA( className, schema )                                                           \
+   IMPLEMENT_CLASS( className, NULL )                                                              \
+   END_IMPLEMENT_CLASS;                                                                            \
+   S32 className::_smTypeId;                                                                       \
+   SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" );      \
+   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }            \
+   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                       \
+   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }  \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; }            \
+   ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
+
+#define IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA( className, schema )                                                           \
+   IMPLEMENT_CLASS( className, NULL )                                                              \
+   END_IMPLEMENT_CLASS;                                                                            \
+   S32 className::_smTypeId;                                                                       \
+   SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" );      \
+   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }            \
+   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                       \
+   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }  \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }                 \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; }            \
    ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
 
 #define IMPLEMENT_CO_NETOBJECT_V1( className )                                                           \
@@ -1071,6 +1180,8 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                  \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                             \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }        \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }        \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
    ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeObject, 0, className::getParentStaticClassRep(), &Parent::__description )
 
 #define IMPLEMENT_CO_DATABLOCK_V1( className )                                                           \
@@ -1081,8 +1192,10 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }                  \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                             \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }        \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
    ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeDataBlock, 0, className::getParentStaticClassRep(), &Parent::__description )
-   
+
 // Support for adding properties to classes CONOBJECT style.
 #define PROPERTY_TABLE( className )                                                                      \
    namespace { namespace _ ## className {                                                                \
@@ -1092,13 +1205,13 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    ConcreteClassRep< className >::smPropertyTable = _ ## className::_propTable;                          \
    namespace { namespace _ ## className {                                                                \
       EnginePropertyTable::Property _props[] = {
-      
+
 #define END_PROPERTY_TABLE                                                                               \
          { NULL }                                                                                        \
       };                                                                                                 \
       EnginePropertyTable _propTable( sizeof( _props ) / sizeof( _props[ 0 ] ) - 1, _props );            \
    } }
-   
+
 /// Add an auto-doc for a class.
 #define ConsoleDocClass( className, docString ) \
    CLASSDOC( className, docString )
@@ -1108,7 +1221,7 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
 //------------------------------------------------------------------------------
 // Protected field default get/set functions
 //
-// The reason for these functions is that it will save one branch per console 
+// The reason for these functions is that it will save one branch per console
 // data request and script functions will still execute at the same speed as
 // before the modifications to allow protected static fields. These will just
 // inline and the code should be roughly the same size, and just as fast as
@@ -1133,6 +1246,21 @@ inline const char *emptyStringProtectedGetFn( void *obj, const char *data )
    return "";
 }
 
+inline bool defaultProtectedWriteFn(void* obj, StringTableEntry pFieldName)
+{
+   return true;
+}
+
+inline bool defaultProtectedNotSetFn(void* obj, const char *array, const char* data)
+{
+   return false;
+}
+
+inline bool defaultProtectedNotWriteFn(void* obj, StringTableEntry pFieldName)
+{
+   return false;
+}
+
 /// @}
 
 #endif //_CONSOLEOBJECT_H_

+ 12 - 15
Engine/source/console/consoleParser.cpp

@@ -50,24 +50,21 @@ bool addConsoleParser(char *ext, fnGetCurrentFile gcf, fnGetCurrentLine gcl, fnP
 	AssertFatal(ext && gcf && gcl && p && r, "AddConsoleParser called with one or more NULL arguments");
 
 	ConsoleParser * pParser = new ConsoleParser;
-	if(pParser != NULL)
-	{
-		pParser->ext = ext;
-		pParser->getCurrentFile = gcf;
-		pParser->getCurrentLine = gcl;
-		pParser->parse = p;
-		pParser->restart = r;
-		pParser->setScanBuffer = ssb;
 
-		if(def)
-			gDefaultParser = pParser;
+   pParser->ext = ext;
+   pParser->getCurrentFile = gcf;
+   pParser->getCurrentLine = gcl;
+   pParser->parse = p;
+   pParser->restart = r;
+   pParser->setScanBuffer = ssb;
 
-		pParser->next = gParserList;
-		gParserList = pParser;
+   if (def)
+      gDefaultParser = pParser;
 
-		return true;
-	}
-	return false;
+   pParser->next = gParserList;
+   gParserList = pParser;
+
+   return true;
 }
 
 ConsoleParser * getParserForFile(const char *filename)

+ 25 - 25
Engine/source/console/consoleTypes.cpp

@@ -34,7 +34,7 @@
 //-----------------------------------------------------------------------------
 // TypeString
 //-----------------------------------------------------------------------------
-ConsoleType( string, TypeString, const char* )
+ConsoleType( string, TypeString, const char*, "" )
 ImplementConsoleTypeCasters( TypeString, const char* );
 
 ConsoleGetType( TypeString )
@@ -53,7 +53,7 @@ ConsoleSetType( TypeString )
 //-----------------------------------------------------------------------------
 // TypeCaseString
 //-----------------------------------------------------------------------------
-ConsoleType( caseString, TypeCaseString, const char* )
+ConsoleType(caseString, TypeCaseString, const char*, "")
 
 ConsoleSetType( TypeCaseString )
 {
@@ -71,7 +71,7 @@ ConsoleGetType( TypeCaseString )
 //-----------------------------------------------------------------------------
 // TypeRealString
 //-----------------------------------------------------------------------------
-ConsoleType( string, TypeRealString, String )
+ConsoleType(string, TypeRealString, String, "")
 ImplementConsoleTypeCasters( TypeRealString, String )
 
 ConsoleGetType( TypeRealString )
@@ -94,7 +94,7 @@ ConsoleSetType( TypeRealString )
 //-----------------------------------------------------------------------------
 // TypeCommand
 //-----------------------------------------------------------------------------
-ConsoleType( string, TypeCommand, String )
+ConsoleType(string, TypeCommand, String, "")
 
 ConsoleGetType( TypeCommand )
 {
@@ -284,7 +284,7 @@ ConsoleProcessData( TypeShapeFilename )
 //-----------------------------------------------------------------------------
 // TypeS8
 //-----------------------------------------------------------------------------
-ConsoleType( char, TypeS8, S8 )
+ConsoleType(char, TypeS8, S8, "")
 ImplementConsoleTypeCasters( TypeS8, S8 )
 
 ConsoleGetType( TypeS8 )
@@ -306,7 +306,7 @@ ConsoleSetType( TypeS8 )
 //-----------------------------------------------------------------------------
 // TypeS32
 //-----------------------------------------------------------------------------
-ConsoleType( int, TypeS32, S32 )
+ConsoleType(int, TypeS32, S32, "")
 ImplementConsoleTypeCasters(TypeS32, S32)
 
 ConsoleGetType( TypeS32 )
@@ -329,7 +329,7 @@ ConsoleSetType( TypeS32 )
 //-----------------------------------------------------------------------------
 // TypeS32Vector
 //-----------------------------------------------------------------------------
-ConsoleType( intList, TypeS32Vector, Vector<S32> )
+ConsoleType(intList, TypeS32Vector, Vector<S32>, "")
 ImplementConsoleTypeCasters( TypeS32Vector, Vector< S32 > )
 
 ConsoleGetType( TypeS32Vector )
@@ -386,7 +386,7 @@ ConsoleSetType( TypeS32Vector )
 //-----------------------------------------------------------------------------
 // TypeF32
 //-----------------------------------------------------------------------------
-ConsoleType( float, TypeF32, F32 )
+ConsoleType(float, TypeF32, F32, "")
 ImplementConsoleTypeCasters(TypeF32, F32)
 
 ConsoleGetType( TypeF32 )
@@ -407,7 +407,7 @@ ConsoleSetType( TypeF32 )
 //-----------------------------------------------------------------------------
 // TypeF32Vector
 //-----------------------------------------------------------------------------
-ConsoleType( floatList, TypeF32Vector, Vector<F32> )
+ConsoleType(floatList, TypeF32Vector, Vector<F32>, "")
 ImplementConsoleTypeCasters( TypeF32Vector, Vector< F32 > )
 
 ConsoleGetType( TypeF32Vector )
@@ -464,7 +464,7 @@ ConsoleSetType( TypeF32Vector )
 //-----------------------------------------------------------------------------
 // TypeBool
 //-----------------------------------------------------------------------------
-ConsoleType( bool, TypeBool, bool )
+ConsoleType(bool, TypeBool, bool, "")
 ImplementConsoleTypeCasters( TypeBool, bool )
 
 ConsoleGetType( TypeBool )
@@ -484,7 +484,7 @@ ConsoleSetType( TypeBool )
 //-----------------------------------------------------------------------------
 // TypeBoolVector
 //-----------------------------------------------------------------------------
-ConsoleType( boolList, TypeBoolVector, Vector<bool> )
+ConsoleType(boolList, TypeBoolVector, Vector<bool>, "")
 ImplementConsoleTypeCasters( TypeBoolVector, Vector< bool > )
 
 ConsoleGetType( TypeBoolVector )
@@ -541,7 +541,7 @@ ConsoleSetType( TypeBoolVector )
 //-----------------------------------------------------------------------------
 // TypeFlag
 //-----------------------------------------------------------------------------
-ConsoleType( flag, TypeFlag, S32 )
+ConsoleType(flag, TypeFlag, S32, "")
 
 ConsoleGetType( TypeFlag )
 {
@@ -567,7 +567,7 @@ ConsoleSetType( TypeFlag )
 //-----------------------------------------------------------------------------
 // TypeColorF
 //-----------------------------------------------------------------------------
-ConsoleType( ColorF, TypeColorF, ColorF )
+ConsoleType(ColorF, TypeColorF, ColorF, "")
 ImplementConsoleTypeCasters( TypeColorF, ColorF )
 
 ConsoleGetType( TypeColorF )
@@ -640,7 +640,7 @@ ConsoleSetType( TypeColorF )
 //-----------------------------------------------------------------------------
 // TypeColorI
 //-----------------------------------------------------------------------------
-ConsoleType( ColorI, TypeColorI, ColorI )
+ConsoleType(ColorI, TypeColorI, ColorI, "")
 ImplementConsoleTypeCasters( TypeColorI, ColorI )
 
 ConsoleGetType( TypeColorI )
@@ -713,7 +713,7 @@ ConsoleSetType( TypeColorI )
 //-----------------------------------------------------------------------------
 // TypeSimObjectName
 //-----------------------------------------------------------------------------
-ConsoleType( SimObject, TypeSimObjectName, SimObject* )
+ConsoleType(SimObject, TypeSimObjectName, SimObject*, "")
 
 ConsoleSetType( TypeSimObjectName )
 {
@@ -738,7 +738,7 @@ ConsoleGetType( TypeSimObjectName )
 //-----------------------------------------------------------------------------
 // TypeName
 //-----------------------------------------------------------------------------
-ConsoleType( string, TypeName, const char* )
+ConsoleType(string, TypeName, const char*, "")
 
 ConsoleGetType( TypeName )
 {
@@ -753,7 +753,7 @@ ConsoleSetType( TypeName )
 //------------------------------------------------------------------------------
 // TypeParticleParameterString
 //------------------------------------------------------------------------------
-ConsoleType( string, TypeParticleParameterString, const char* )
+ConsoleType(string, TypeParticleParameterString, const char*, "")
 
 ConsoleGetType( TypeParticleParameterString )
 {
@@ -772,7 +772,7 @@ ConsoleSetType( TypeParticleParameterString )
 // TypeMaterialName
 //-----------------------------------------------------------------------------
 
-ConsoleType( string, TypeMaterialName, String )
+ConsoleType(string, TypeMaterialName, String, "")
 
 ConsoleGetType( TypeMaterialName )
 {
@@ -794,7 +794,7 @@ ConsoleSetType( TypeMaterialName )
 // TypeTerrainMaterialIndex
 //-----------------------------------------------------------------------------
 
-ConsoleType( int, TypeTerrainMaterialIndex, S32 )
+ConsoleType(int, TypeTerrainMaterialIndex, S32, "")
 
 ConsoleGetType( TypeTerrainMaterialIndex )
 {
@@ -816,7 +816,7 @@ ConsoleSetType( TypeTerrainMaterialIndex )
 // TypeTerrainMaterialName
 //-----------------------------------------------------------------------------
 
-ConsoleType( string, TypeTerrainMaterialName, const char* )
+ConsoleType(string, TypeTerrainMaterialName, const char*, "")
 
 ConsoleGetType( TypeTerrainMaterialName )
 {
@@ -835,7 +835,7 @@ ConsoleSetType( TypeTerrainMaterialName )
 // TypeCubemapName
 //-----------------------------------------------------------------------------
 
-ConsoleType( string, TypeCubemapName, String )
+ConsoleType(string, TypeCubemapName, String, "")
 
 ConsoleGetType( TypeCubemapName )
 {
@@ -856,7 +856,7 @@ ConsoleSetType( TypeCubemapName )
 //-----------------------------------------------------------------------------
 // TypeRectUV
 //-----------------------------------------------------------------------------
-ConsoleType( RectF, TypeRectUV, RectF )
+ConsoleType(RectF, TypeRectUV, RectF, "")
 
 ConsoleGetType( TypeRectUV )
 {
@@ -882,7 +882,7 @@ ConsoleSetType( TypeRectUV )
 //-----------------------------------------------------------------------------
 // TypeUUID
 //-----------------------------------------------------------------------------
-ConsoleType( uuid, TypeUUID, Torque::UUID )
+ConsoleType(uuid, TypeUUID, Torque::UUID, "")
 ImplementConsoleTypeCasters( TypeUUID, Torque::UUID )
 
 ConsoleGetType( TypeUUID )
@@ -906,7 +906,7 @@ ConsoleSetType( TypeUUID )
 //-----------------------------------------------------------------------------
 // TypePID
 //-----------------------------------------------------------------------------
-ConsoleType( pid, TypePID, SimPersistID* )
+ConsoleType(pid, TypePID, SimPersistID*, "")
 ImplementConsoleTypeCasters( TypePID, SimPersistID* )
 
 ConsoleGetType( TypePID )
@@ -945,7 +945,7 @@ ConsoleSetType( TypePID )
 //-----------------------------------------------------------------------------
 // TypeSimPersistId
 //-----------------------------------------------------------------------------
-ConsoleType( SimPersistId, TypeSimPersistId, SimPersistID* )
+ConsoleType(SimPersistId, TypeSimPersistId, SimPersistID*, "")
 
 ConsoleGetType( TypeSimPersistId )
 {

+ 1 - 5
Engine/source/console/consoleTypes.h

@@ -48,11 +48,7 @@
 /// @{
 
 #ifndef Offset
-#if defined(TORQUE_COMPILER_GCC) && (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))
-#define Offset(m,T) ((int)(&((T *)1)->m) - 1)
-#else
-#define Offset(x, cls) ((dsize_t)((const char *)&(((cls *)0)->x)-(const char *)0))
-#endif
+#define Offset(x, cls) offsetof(cls, x)
 #endif
 
 class GFXShader;

+ 18 - 1
Engine/source/console/dynamicTypes.h

@@ -35,6 +35,9 @@
 #include "console/engineTypeInfo.h"
 #endif
 
+#ifndef _STRINGTABLE_H_
+#include "core/stringTable.h"
+#endif
 
 /// @file
 /// Support for legacy TorqueScript console types.
@@ -151,6 +154,8 @@ class ConsoleBaseType
       virtual const bool isDatablock() { return false; };
       
       virtual const char* prepData( const char* data, char* buffer, U32 bufferLen ) { return data; };
+
+      virtual StringTableEntry getTypePrefix(void) const { return StringTable->EmptyString(); }
       
       /// @}
 };
@@ -259,7 +264,7 @@ const EngineTypeInfo* _MAPTYPE() { return TYPE< T >(); }
    DefineConsoleType( type, nativeType ) \
    template<> inline const EngineTypeInfo* _MAPTYPE< nativeType >() { return NULL; }
 
-#define ConsoleType( typeName, type, nativeType ) \
+#define ConsoleType( typeName, type, nativeType, typePrefix ) \
    S32 type; \
    class ConsoleType##type : public ConsoleBaseType \
    { \
@@ -275,6 +280,7 @@ const EngineTypeInfo* _MAPTYPE() { return TYPE< T >(); }
       virtual const char *getTypeClassName() { return #typeName ; } \
       virtual void       *getNativeVariable() { T* var = new T; return (void*)var; } \
       virtual void        deleteNativeVariable(void* var) { T* nativeVar = reinterpret_cast<T*>(var); delete nativeVar; } \
+      virtual StringTableEntry getTypePrefix( void ) const { return StringTable->insert( typePrefix ); } \
    }; \
    ConsoleType ## type gConsoleType ## type ## Instance;
 
@@ -304,6 +310,9 @@ const EngineTypeInfo* _MAPTYPE() { return TYPE< T >(); }
    }; \
    ConsoleType ## type gConsoleType ## type ## Instance;
 
+#define ConsoleTypeFieldPrefix( type, typePrefix ) \
+   StringTableEntry ConsoleType##type::getTypePrefix( void ) const { return StringTable->insert( typePrefix ); }
+
 #define ConsoleSetType( type ) \
    void ConsoleType##type::setData(void *dptr, S32 argc, const char **argv, const EnumTable *tbl, BitSet32 flag)
 
@@ -318,6 +327,10 @@ const EngineTypeInfo* _MAPTYPE() { return TYPE< T >(); }
    DECLARE_ENUM( type ); \
    DefineConsoleType( Type ## type, type );
 
+#define DefineEnumType_R( type ) \
+   DECLARE_ENUM_R( type ); \
+   DefineConsoleType( Type ## type, type );
+
 #define _ConsoleEnumType( typeName, type, nativeType ) \
    S32 type; \
    ImplementConsoleTypeCasters( type, nativeType ) \
@@ -347,6 +360,10 @@ const EngineTypeInfo* _MAPTYPE() { return TYPE< T >(); }
    DECLARE_BITFIELD( type ); \
    DefineConsoleType( Type ## type, type );
 
+#define DefineBitfieldType_R( type ) \
+   DECLARE_BITFIELD_R( type ); \
+   DefineConsoleType( Type ## type, type );
+
 #define _ConsoleBitfieldType( typeName, type, nativeType ) \
    S32 type; \
    ImplementConsoleTypeCasters( type, nativeType ) \

+ 1 - 1
Engine/source/console/engineDoc.cpp

@@ -706,7 +706,7 @@ static bool dumpEngineDocs( const char *outputFile )
    // Dump pre-declarations for any groups we encountered
    // so that we don't have to explicitly define them.
    HashTable<String,U32>::Iterator iter = smDocGroups.begin();
-   for ( ; iter != smDocGroups.end(); iter++ )
+   for (; iter != smDocGroups.end(); ++iter)
       stream.writeText( String::ToString( "/*! @addtogroup %s */\r\n\r\n", iter->key.c_str() ) );
 
    return true;

+ 4 - 0
Engine/source/console/engineFunctions.h

@@ -77,7 +77,11 @@ struct EngineFunctionDefaultArguments
 
 
 // Need byte-aligned packing for the default argument structures.
+#ifdef _WIN64
+#pragma pack( push, 4 )
+#else
 #pragma pack( push, 1 )
+#endif
    
 
 // Structure encapsulating default arguments to an engine API function.

+ 9 - 9
Engine/source/console/enginePrimitives.h

@@ -34,14 +34,14 @@
 
 
 
-DECLARE_PRIMITIVE( bool );
-DECLARE_PRIMITIVE( S8 );
-DECLARE_PRIMITIVE( U8 );
-DECLARE_PRIMITIVE( S32 );
-DECLARE_PRIMITIVE( U32 );
-DECLARE_PRIMITIVE( F32 );
-DECLARE_PRIMITIVE( F64 );
-DECLARE_PRIMITIVE( void* );
+DECLARE_PRIMITIVE_R( bool );
+DECLARE_PRIMITIVE_R(S8);
+DECLARE_PRIMITIVE_R(U8);
+DECLARE_PRIMITIVE_R(S32);
+DECLARE_PRIMITIVE_R(U32);
+DECLARE_PRIMITIVE_R(F32);
+DECLARE_PRIMITIVE_R(F64);
+DECLARE_PRIMITIVE_R(void*);
 
 
 //FIXME: this allows String to be used as a struct field type
@@ -52,7 +52,7 @@ DECLARE_PRIMITIVE( void* );
 // are considered to be owned by the API layer itself.  The rule here is that such
 // a string is only valid until the next API call is made.  Usually, control layers
 // will immediately copy and convert strings to their own string type.
-_DECLARE_TYPE( String );
+_DECLARE_TYPE_R(String);
 template<>
 struct EngineTypeTraits< String > : public _EnginePrimitiveTypeTraits< String >
 {

+ 6 - 6
Engine/source/console/engineStructs.h

@@ -41,11 +41,11 @@ class ColorI;
 class ColorF;
 
 
-DECLARE_STRUCT( Vector< bool > );
-DECLARE_STRUCT( Vector< S32 > );
-DECLARE_STRUCT( Vector< F32 > );
-DECLARE_STRUCT( Torque::UUID );
-DECLARE_STRUCT( ColorI );
-DECLARE_STRUCT( ColorF );
+DECLARE_STRUCT_R(Vector< bool >);
+DECLARE_STRUCT_R(Vector< S32 >);
+DECLARE_STRUCT_R(Vector< F32 >);
+DECLARE_STRUCT_R(Torque::UUID);
+DECLARE_STRUCT_R(ColorI);
+DECLARE_STRUCT_R(ColorF);
 
 #endif // !_ENGINESTRUCTS_H_

+ 3 - 3
Engine/source/console/engineTypeInfo.h

@@ -44,7 +44,7 @@ enum EngineTypeKind
    EngineTypeKindClass           ///< Pointer to opaque EngineObject.
 };
 
-DECLARE_ENUM( EngineTypeKind );
+DECLARE_ENUM_R( EngineTypeKind );
 
 /// Flags for an EngineTypeInfo.
 enum EngineTypeFlags
@@ -173,8 +173,8 @@ class EngineFieldTable
       /// Construct a field table from a NULL-terminated array of Field
       /// records.
       EngineFieldTable( const Field* fields )
-         : mFields( fields ),
-           mNumFields( 0 )
+         : mNumFields( 0 ),
+           mFields( fields )
       {
          while( fields[ mNumFields ].getName() )
             mNumFields ++;

+ 47 - 1
Engine/source/console/engineTypes.h

@@ -416,6 +416,16 @@ namespace _Private {
 
 
 #define _DECLARE_TYPE( type )                                                                \
+   template<> const EngineTypeInfo* TYPE< type >();                                          \
+   template<> struct _SCOPE< type > {                                                        \
+      EngineExportScope& operator()() const {                                                \
+         return *static_cast< EngineExportScope* >(                                          \
+            const_cast< EngineTypeInfo* >( ( TYPE< type >() ) )                              \
+         );                                                                                  \
+      }                                                                                      \
+   };
+
+#define _DECLARE_TYPE_R( type )                                                              \
    template<> const EngineTypeInfo* TYPE< type >();                                          \
    template<> struct _SCOPE< type > {                                                        \
       EngineExportScope& operator()() const {                                                \
@@ -432,22 +442,42 @@ namespace _Private {
    _DECLARE_TYPE( type )                                                                     \
    template<>                                                                                \
    struct EngineTypeTraits< type > : public _EnginePrimitiveTypeTraits< type > {};
+
+#define _DECLARE_PRIMITIVE_R( type )                                                         \
+   _DECLARE_TYPE_R( type )                                                                   \
+   template<>                                                                                \
+   struct EngineTypeTraits< type > : public _EnginePrimitiveTypeTraits< type > {};
    
 #define _DECLARE_ENUM( type )                                                                \
    _DECLARE_TYPE( type )                                                                     \
    template<>                                                                                \
    struct _EngineTypeTraits< type > : public _EngineEnumTypeTraits< type > {};
-   
+
+#define _DECLARE_ENUM_R( type )                                                              \
+   _DECLARE_TYPE_R( type )                                                                   \
+   template<>                                                                                \
+   struct _EngineTypeTraits< type > : public _EngineEnumTypeTraits< type > {};
+
 #define _DECLARE_BITFIELD( type )                                                            \
    _DECLARE_TYPE( type )                                                                     \
    template<>                                                                                \
    struct _EngineTypeTraits< type > : public _EngineBitfieldTypeTraits< type > {};
 
+#define _DECLARE_BITFIELD_R( type )                                                            \
+   _DECLARE_TYPE_R( type )                                                                     \
+   template<>                                                                                \
+   struct _EngineTypeTraits< type > : public _EngineBitfieldTypeTraits< type > {};
+
+
 #define _DECLARE_STRUCT( type )                                                              \
    _DECLARE_TYPE( type )                                                                     \
    template<>                                                                                \
    struct _EngineTypeTraits< type > : public _EngineStructTypeTraits< type > {};
 
+#define _DECLARE_STRUCT_R( type )                                                            \
+   _DECLARE_TYPE_R( type )                                                                   \
+   template<>                                                                                \
+   struct _EngineTypeTraits< type > : public _EngineStructTypeTraits< type > {};
 
 #define _IMPLEMENT_TYPE( type, exportName )        \
    template<>                                      \
@@ -524,6 +554,10 @@ namespace _Private {
 #define DECLARE_PRIMITIVE( type ) \
    _DECLARE_PRIMITIVE( type )
 
+///
+#define DECLARE_PRIMITIVE_R( type ) \
+   _DECLARE_PRIMITIVE_R( type )
+
 ///
 #define IMPLEMENT_PRIMITIVE( type, exportName, scope, doc ) \
    _IMPLEMENT_PRIMITIVE( type, exportName, scope, doc )
@@ -531,11 +565,19 @@ namespace _Private {
 ///
 #define DECLARE_ENUM( type ) \
    _DECLARE_ENUM( type )
+
+///
+#define DECLARE_ENUM_R( type ) \
+   _DECLARE_ENUM_R( type )
    
 ///
 #define DECLARE_BITFIELD( type ) \
    _DECLARE_BITFIELD( type )
 
+///
+#define DECLARE_BITFIELD_R( type ) \
+   _DECLARE_BITFIELD_R( type )
+
 ///
 #define IMPLEMENT_ENUM( type, exportName, scope, doc ) \
    _IMPLEMENT_ENUM( type, exportName, scope, doc )
@@ -556,6 +598,10 @@ namespace _Private {
 #define DECLARE_STRUCT( type ) \
    _DECLARE_STRUCT( type )
 
+///
+#define DECLARE_STRUCT_R( type ) \
+   _DECLARE_STRUCT_R( type )
+
 ///
 #define IMPLEMENT_STRUCT( type, exportName, scope, doc ) \
    _IMPLEMENT_STRUCT( type, exportName, scope, doc )

+ 1 - 1
Engine/source/console/fieldBrushObject.cpp

@@ -216,7 +216,7 @@ DefineConsoleMethod(FieldBrushObject, queryFields, const char*, (const char* sim
     const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
 
     // Did we specify a groups list?
-    if ( dStrIsEmpty(groupList) )
+    if ( String::isEmpty(groupList) )
     {
         // No, so return all fields...
 

+ 9 - 9
Engine/source/console/fileSystemFunctions.cpp

@@ -137,7 +137,7 @@ static S32 buildFileList(const char* pattern, bool recurse, bool multiMatch)
 
 //-----------------------------------------------------------------------------
 
-DefineEngineFunction( findFirstFile, String, ( const char* pattern, bool recurse ), ( true ),
+DefineEngineFunction( findFirstFile, String, ( const char* pattern, bool recurse ), ( "", true ),
    "@brief Returns the first file in the directory system matching the given pattern.\n\n"
 
    "Use the corresponding findNextFile() to step through "
@@ -209,7 +209,7 @@ DefineEngineFunction( findNextFile, String, ( const char* pattern ), ( "" ),
 
 //-----------------------------------------------------------------------------
 
-DefineEngineFunction( getFileCount, S32, ( const char* pattern, bool recurse ), ( true ),
+DefineEngineFunction( getFileCount, S32, ( const char* pattern, bool recurse ), ( "", true ),
 	"@brief Returns the number of files in the directory tree that match the given patterns\n\n"
 
    "This function differs from getFileCountMultiExpr() in that it supports a single search "
@@ -245,7 +245,7 @@ DefineEngineFunction( getFileCount, S32, ( const char* pattern, bool recurse ),
 
 //-----------------------------------------------------------------------------
 
-DefineEngineFunction(findFirstFileMultiExpr, String, ( const char* pattern, bool recurse ), (true),
+DefineEngineFunction(findFirstFileMultiExpr, String, ( const char* pattern, bool recurse ), ( "", true),
 	"@brief Returns the first file in the directory system matching the given patterns.\n\n"
 
    "Use the corresponding findNextFileMultiExpr() to step through "
@@ -327,7 +327,7 @@ DefineEngineFunction(findNextFileMultiExpr, String, ( const char* pattern ), (""
    return sgFindFilesResults[sgFindFilesPos++];
 }
 
-DefineEngineFunction(getFileCountMultiExpr, S32, ( const char* pattern, bool recurse ), (true),
+DefineEngineFunction(getFileCountMultiExpr, S32, ( const char* pattern, bool recurse ), ( "", true),
 	"@brief Returns the number of files in the directory tree that match the given patterns\n\n"
 
    "If you're interested in a list of files that match the given patterns and not just "
@@ -452,7 +452,7 @@ DefineEngineFunction(stopFileChangeNotifications, void, (),,
 }
 
 
-DefineEngineFunction(getDirectoryList, String, ( const char* path, S32 depth ), ( 0 ),
+DefineEngineFunction(getDirectoryList, String, ( const char* path, S32 depth ), ( "", 0 ),
 	"@brief Gathers a list of directories starting at the given path.\n\n"
 
 	"@param path String containing the path of the directory\n"
@@ -686,7 +686,7 @@ DefineEngineFunction(getWorkingDirectory, String, (),,
 // are just string processing functions. They are needed by the 3D tools which
 // are not currently built with TORQUE_TOOLS defined.
 
-DefineEngineFunction(makeFullPath, String, ( const char* path, const char* cwd ), (""),
+DefineEngineFunction(makeFullPath, String, ( const char* path, const char* cwd ), ( "", ""),
 	"@brief Converts a relative file path to a full path\n\n"
 
 	"For example, \"./console.log\" becomes \"C:/Torque/t3d/examples/FPS Example/game/console.log\"\n"
@@ -701,7 +701,7 @@ DefineEngineFunction(makeFullPath, String, ( const char* path, const char* cwd )
    return buf;
 }
 
-DefineEngineFunction(makeRelativePath, String, ( const char* path, const char* to ), (""),
+DefineEngineFunction(makeRelativePath, String, ( const char* path, const char* to ), ( "", ""),
 	"@brief Turns a full or local path to a relative one\n\n"
 
    "For example, \"./game/art\" becomes \"game/art\"\n"
@@ -714,7 +714,7 @@ DefineEngineFunction(makeRelativePath, String, ( const char* path, const char* t
    return Platform::makeRelativePathName( path, dStrlen(to) > 1 ? to : NULL );
 }
 
-DefineEngineFunction(pathConcat, String, ( const char* path, const char* file),,
+DefineEngineFunction(pathConcat, String, ( const char* path, const char* file), ( "", ""),
 	"@brief Combines two separate strings containing a file path and file name together into a single string\n\n"
 
 	"@param path String containing file path\n"
@@ -783,7 +783,7 @@ DefineEngineFunction( openFile, void, ( const char* file ),,
 
 //-----------------------------------------------------------------------------
 
-DefineEngineFunction( pathCopy, bool, ( const char* fromFile, const char* toFile, bool noOverwrite ), ( true ),
+DefineEngineFunction( pathCopy, bool, ( const char* fromFile, const char* toFile, bool noOverwrite ), ( "", "", true ),
    "@brief Copy a file to a new location.\n"
    "@param fromFile %Path of the file to copy.\n"
    "@param toFile %Path where to copy @a fromFile to.\n"

+ 21 - 0
Engine/source/console/runtimeClassRep.h

@@ -60,6 +60,27 @@ public:
       parentClass     = parent;
    };
 
+   virtual AbstractClassRep* getContainerChildClass(const bool recurse)
+   {
+      // Fetch container children type.
+      AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
+      if (!recurse || pChildren != NULL)
+         return pChildren;
+
+      // Fetch parent type.
+      AbstractClassRep* pParent = T::getParentStaticClassRep();
+      if (pParent == NULL)
+         return NULL;
+
+      // Get parent container children.
+      return pParent->getContainerChildClass(recurse);
+   }
+
+   virtual WriteCustomTamlSchema getCustomTamlSchema(void)
+   {
+      return T::getStaticWriteCustomTamlSchema();
+   }
+
    /// Perform class specific initialization tasks.
    ///
    /// Link namespaces, call initPersistFields() and consoleInit().

+ 5 - 0
Engine/source/console/scriptFilename.cpp

@@ -230,6 +230,11 @@ bool expandOldScriptFilename(char *filename, U32 size, const char *src)
    else if (dStrncmp(src, "./", 2) == 0)
       // dot path means load from current codeblock/mod path
       slash = dStrrchr(cbName, '/');
+   else if (dStrncmp(src, "^", 1) == 0)
+   {
+      Platform::makeFullPathName(src + 1, filename, size);
+      return true;
+   }
    else
    {
       // otherwise path must be fully specified

+ 1 - 1
Engine/source/console/sim.h

@@ -64,7 +64,7 @@ typedef U32 SimObjectId;
 enum SimObjectsConstants
 {
    DataBlockObjectIdFirst = 3,
-   DataBlockObjectIdBitSize = 10,
+   DataBlockObjectIdBitSize = 14,
    DataBlockObjectIdLast = DataBlockObjectIdFirst + (1 << DataBlockObjectIdBitSize) - 1,
 
    MessageObjectIdFirst = DataBlockObjectIdLast + 1,

+ 1 - 1
Engine/source/console/simFieldDictionary.h

@@ -49,13 +49,13 @@ public:
       Entry *next;
       ConsoleBaseType *type;
    };
-private:
    enum
    {
       HashTableSize = 19
    };
    Entry *mHashTable[HashTableSize];
 
+private:
    static Entry   *smFreeList;
 
    void           freeEntry(Entry *entry);

+ 306 - 1
Engine/source/console/simObject.cpp

@@ -34,7 +34,7 @@
 #include "core/frameAllocator.h"
 #include "core/stream/fileStream.h"
 #include "core/fileObject.h"
-
+#include "persistence/taml/tamlCustom.h"
 
 IMPLEMENT_CONOBJECT( SimObject );
 
@@ -437,6 +437,97 @@ SimPersistID* SimObject::getOrCreatePersistentId()
    return mPersistentId;
 }
 
+
+
+void SimObject::onTamlCustomRead(TamlCustomNodes const& customNodes)
+{
+   // Debug Profiling.
+   //PROFILE_SCOPE(SimObject_OnTamlCustomRead);
+
+   // Fetch field list.
+   const AbstractClassRep::FieldList& fieldList = getFieldList();
+   const U32 fieldCount = fieldList.size();
+   for (U32 index = 0; index < fieldCount; ++index)
+   {
+      // Fetch field.
+      const AbstractClassRep::Field* pField = &fieldList[index];
+
+      // Ignore if field not appropriate.
+      if (pField->type == AbstractClassRep::StartArrayFieldType || pField->elementCount > 1)
+      {
+         // Find cell custom node.
+         const TamlCustomNode* pCustomCellNodes = NULL;
+         if (pField->pGroupname != NULL)
+            pCustomCellNodes = customNodes.findNode(pField->pGroupname);
+         if (!pCustomCellNodes)
+         {
+            char* niceFieldName = const_cast<char *>(pField->pFieldname);
+            niceFieldName[0] = dToupper(niceFieldName[0]);
+            String str_niceFieldName = String(niceFieldName);
+            pCustomCellNodes = customNodes.findNode(str_niceFieldName + "s");
+         }
+
+         // Continue if we have explicit cells.
+         if (pCustomCellNodes != NULL)
+         {
+            // Fetch children cell nodes.
+            const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
+
+            U8 idx = 0;
+            // Iterate cells.
+            for (TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr)
+            {
+               char buf[5];
+               dSprintf(buf, 5, "%d", idx);
+
+               // Fetch cell node.
+               TamlCustomNode* pCellNode = *cellNodeItr;
+
+               // Fetch node name.
+               StringTableEntry nodeName = pCellNode->getNodeName();
+
+               // Is this a valid alias?
+               if (nodeName != pField->pFieldname)
+               {
+                  // No, so warn.
+                  Con::warnf("SimObject::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, pField->pFieldname);
+                  continue;
+               }
+
+               // Fetch fields.
+               const TamlCustomFieldVector& fields = pCellNode->getFields();
+
+               // Iterate property fields.
+               for (TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr)
+               {
+                  // Fetch field.
+                  const TamlCustomField* pField = *fieldItr;
+
+                  // Fetch field name.
+                  StringTableEntry fieldName = pField->getFieldName();
+
+                  const AbstractClassRep::Field* field = findField(fieldName);
+
+                  // Check common fields.
+                  if (field)
+                  {
+                     setDataField(fieldName, buf, pField->getFieldValue());
+                  }
+                  else
+                  {
+                     // Unknown name so warn.
+                     Con::warnf("SimObject::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName);
+                     continue;
+                  }
+               }
+
+               idx++;
+            }
+         }
+      }
+   }
+}
+
 //-----------------------------------------------------------------------------
 
 bool SimObject::_setPersistentID( void* object, const char* index, const char* data )
@@ -925,6 +1016,220 @@ const char *SimObject::getDataField(StringTableEntry slotName, const char *array
    return "";
 }
 
+
+const char *SimObject::getPrefixedDataField(StringTableEntry fieldName, const char *array)
+{
+   // Sanity!
+   AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
+
+   // Fetch field value.
+   const char* pFieldValue = getDataField(fieldName, array);
+
+   // Sanity.
+   //AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
+   if (!pFieldValue)
+      return NULL;
+
+   // Return without the prefix if there's no value.
+   if (*pFieldValue == 0)
+      return StringTable->EmptyString();
+
+   // Fetch the field prefix.
+   StringTableEntry fieldPrefix = getDataFieldPrefix(fieldName);
+
+   // Sanity!
+   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
+
+   // Calculate a buffer size including prefix.
+   const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
+
+   // Fetch a buffer.
+   char* pValueBuffer = Con::getReturnBuffer(valueBufferSize);
+
+   // Format the value buffer.
+   dSprintf(pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue);
+
+   return pValueBuffer;
+}
+
+//-----------------------------------------------------------------------------
+
+void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value)
+{
+   // Sanity!
+   AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
+   AssertFatal(value != NULL, "Field value cannot be NULL.");
+
+   // Set value without prefix if there's no value.
+   if (*value == 0)
+   {
+      setDataField(fieldName, NULL, value);
+      return;
+   }
+
+   // Fetch the field prefix.
+   StringTableEntry fieldPrefix = getDataFieldPrefix(fieldName);
+
+   // Sanity.
+   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
+
+   // Do we have a field prefix?
+   if (fieldPrefix == StringTable->EmptyString())
+   {
+      // No, so set the data field in the usual way.
+      setDataField(fieldName, NULL, value);
+      return;
+   }
+
+   // Yes, so fetch the length of the field prefix.
+   const U32 fieldPrefixLength = dStrlen(fieldPrefix);
+
+   // Yes, so does it start with the object field prefix?
+   if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
+   {
+      // No, so set the data field in the usual way.
+      setDataField(fieldName, NULL, value);
+      return;
+   }
+
+   // Yes, so set the data excluding the prefix.
+   setDataField(fieldName, NULL, value + fieldPrefixLength);
+}
+
+//-----------------------------------------------------------------------------
+
+const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType)
+{
+   // Sanity!
+   AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
+
+   // Fetch field value.
+   const char* pFieldValue = getDataField(fieldName, array);
+
+   // Sanity.
+   AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
+
+   // Return the field if no field type is specified.
+   if (fieldType == -1)
+      return pFieldValue;
+
+   // Return without the prefix if there's no value.
+   if (*pFieldValue == 0)
+      return StringTable->EmptyString();
+
+   // Fetch the console base type.
+   ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(fieldType);
+
+   // Did we find the console base type?
+   if (pConsoleBaseType == NULL)
+   {
+      // No, so warn.
+      Con::warnf("getPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
+         fieldType, fieldName, pFieldValue);
+   }
+
+   // Fetch the field prefix.
+   StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
+
+   // Sanity!
+   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
+
+   // Calculate a buffer size including prefix.
+   const U32 valueBufferSize = dStrlen(fieldPrefix) + dStrlen(pFieldValue) + 1;
+
+   // Fetch a buffer.
+   char* pValueBuffer = Con::getReturnBuffer(valueBufferSize);
+
+   // Format the value buffer.
+   dSprintf(pValueBuffer, valueBufferSize, "%s%s", fieldPrefix, pFieldValue);
+
+   return pValueBuffer;
+}
+
+//-----------------------------------------------------------------------------
+
+void SimObject::setPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const char *value, const S32 fieldType)
+{
+   // Sanity!
+   AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
+   AssertFatal(value != NULL, "Field value cannot be NULL.");
+
+   // Set value without prefix if no field type was specified.
+   if (fieldType == -1)
+   {
+      setDataField(fieldName, NULL, value);
+      return;
+   }
+
+   // Fetch the console base type.
+   ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(fieldType);
+
+   // Did we find the console base type?
+   if (pConsoleBaseType == NULL)
+   {
+      // No, so warn.
+      Con::warnf("setPrefixedDynamicDataField() - Invalid field type '%d' specified for field '%s' with value '%s'.",
+         fieldType, fieldName, value);
+   }
+
+   // Set value without prefix if there's no value or we didn't find the console base type.
+   if (*value == 0 || pConsoleBaseType == NULL)
+   {
+      setDataField(fieldName, NULL, value);
+      return;
+   }
+
+   // Fetch the field prefix.
+   StringTableEntry fieldPrefix = pConsoleBaseType->getTypePrefix();
+
+   // Sanity.
+   AssertFatal(fieldPrefix != NULL, "Field prefix cannot be NULL.");
+
+   // Do we have a field prefix?
+   if (fieldPrefix == StringTable->EmptyString())
+   {
+      // No, so set the data field in the usual way.
+      setDataField(fieldName, NULL, value);
+      return;
+   }
+
+   // Yes, so fetch the length of the field prefix.
+   const U32 fieldPrefixLength = dStrlen(fieldPrefix);
+
+   // Yes, so does it start with the object field prefix?
+   if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
+   {
+      // No, so set the data field in the usual way.
+      setDataField(fieldName, NULL, value);
+      return;
+   }
+
+   // Yes, so set the data excluding the prefix.
+   setDataField(fieldName, NULL, value + fieldPrefixLength);
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry SimObject::getDataFieldPrefix(StringTableEntry fieldName)
+{
+   // Sanity!
+   AssertFatal(fieldName != NULL, "Cannot get field prefix with NULL field name.");
+
+   // Find the field.
+   const AbstractClassRep::Field* pField = findField(fieldName);
+
+   // Return nothing if field was not found.
+   if (pField == NULL)
+      return StringTable->EmptyString();
+
+   // Yes, so fetch the console base type.
+   ConsoleBaseType* pConsoleBaseType = ConsoleBaseType::getType(pField->type);
+
+   // Fetch the type prefix.
+   return pConsoleBaseType->getTypePrefix();
+}
+
+
 //-----------------------------------------------------------------------------
 
 U32 SimObject::getDataFieldType( StringTableEntry slotName, const char* array )

+ 45 - 1
Engine/source/console/simObject.h

@@ -33,6 +33,9 @@
    #include "core/bitSet.h"
 #endif
 
+#ifndef _TAML_CALLBACKS_H_
+#include "persistence/taml/tamlCallbacks.h"
+#endif
 
 class Stream;
 class LightManager;
@@ -226,7 +229,7 @@ class SimPersistID;
 /// set automatically by the console constructor code.
 ///
 /// @nosubgrouping
-class SimObject: public ConsoleObject
+class SimObject: public ConsoleObject, public TamlCallbacks
 {
    public:
    
@@ -298,6 +301,8 @@ class SimObject: public ConsoleObject
       /// Flags internal to the object management system.
       BitSet32    mFlags;
 
+      StringTableEntry    mProgenitorFile;
+
       /// Object we are copying fields from.
       SimObject* mCopySource;
 
@@ -348,13 +353,42 @@ class SimObject: public ConsoleObject
       static bool setSuperClass(void *object, const char *index, const char *data)     
          { static_cast<SimObject*>(object)->setSuperClassNamespace(data); return false; };
 
+            static bool writeObjectName(void* obj, StringTableEntry pFieldName)
+         { SimObject* simObject = static_cast<SimObject*>(obj); return simObject->objectName != NULL && simObject->objectName != StringTable->EmptyString(); }
+      static bool writeCanSaveDynamicFields(void* obj, StringTableEntry pFieldName)  
+         { return static_cast<SimObject*>(obj)->mCanSaveFieldDictionary == false; }
+      static bool writeInternalName(void* obj, StringTableEntry pFieldName)          
+         { SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mInternalName != NULL && simObject->mInternalName != StringTable->EmptyString(); }
+      static bool setParentGroup(void* obj, const char* data);
+      static bool writeParentGroup(void* obj, StringTableEntry pFieldName)           
+         { return static_cast<SimObject*>(obj)->mGroup != NULL; }
+      static bool writeSuperclass(void* obj, StringTableEntry pFieldName)            
+         { SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mSuperClassName != NULL && simObject->mSuperClassName != StringTable->EmptyString(); }
+      static bool writeClass(void* obj, StringTableEntry pFieldName)                 
+         { SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mClassName != NULL && simObject->mClassName != StringTable->EmptyString(); }
+      static bool writeClassName(void* obj, StringTableEntry pFieldName)
+         { SimObject* simObject = static_cast<SimObject*>(obj); return simObject->mClassName != NULL && simObject->mClassName != StringTable->EmptyString(); }
+
+      
       // Group hierarchy protected set method 
       static bool setProtectedParent(void *object, const char *index, const char *data);
 
       // Object name protected set method
       static bool setProtectedName(void *object, const char *index, const char *data);
 
+   public:
+      inline void setProgenitorFile(const char* pFile) { mProgenitorFile = StringTable->insert(pFile); }
+      inline StringTableEntry getProgenitorFile(void) const { return mProgenitorFile; }
+
    protected:
+      /// Taml callbacks.
+      virtual void onTamlPreWrite(void) {}
+      virtual void onTamlPostWrite(void) {}
+      virtual void onTamlPreRead(void) {}
+      virtual void onTamlPostRead(const TamlCustomNodes& customNodes) {}
+      virtual void onTamlAddParent(SimObject* pParentObject) {}
+      virtual void onTamlCustomWrite(TamlCustomNodes& customNodes) {}
+      virtual void onTamlCustomRead(const TamlCustomNodes& customNodes);
    
       /// Id number for this object.
       SimObjectId mId;
@@ -461,6 +495,16 @@ class SimObject: public ConsoleObject
       /// @param   value       Value to store.
       void setDataField(StringTableEntry slotName, const char *array, const char *value);
 
+      const char *getPrefixedDataField(StringTableEntry fieldName, const char *array);
+
+      void setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value);
+
+      const char *getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType = -1);
+
+      void setPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const char *value, const S32 fieldType = -1);
+
+      StringTableEntry getDataFieldPrefix(StringTableEntry fieldName);
+
       /// Get the type of a field on the object.
       ///
       /// @param   slotName    Field to access.

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