Procházet zdrojové kódy

initial commit

change the macro to use the refactor (exact same structure as the imageasset macro)
marauder2k7 před 2 měsíci
rodič
revize
ca1604170d

+ 80 - 1
Engine/source/T3D/assets/ShapeAsset.cpp

@@ -117,6 +117,54 @@ ConsoleSetType(TypeShapeAssetId)
 
 //-----------------------------------------------------------------------------
 
+//-----------------------------------------------------------------------------
+// REFACTOR
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_STRUCT(AssetPtr<ShapeAsset>, AssetPtrShapeAsset, , "")
+END_IMPLEMENT_STRUCT
+
+ConsoleType(ShapeAssetPtrRefactor, TypeShapeAssetPtrRefactor, AssetPtr<ShapeAsset>, ASSET_ID_FIELD_PREFIX)
+
+
+ConsoleGetType(TypeShapeAssetPtrRefactor)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ShapeAsset>*)dptr)).getAssetId();
+}
+
+ConsoleSetType(TypeShapeAssetPtrRefactor)
+{
+   // 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)
+      {
+         Con::warnf("(TypeShapeAssetPtrRefactor) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeShapeAssetPtrRefactor) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+// REFACTOR END
+//-----------------------------------------------------------------------------
+
 const String ShapeAsset::mErrCodeStrings[] =
 {
    "TooManyVerts",
@@ -478,7 +526,38 @@ StringTableEntry ShapeAsset::getAssetIdByFilename(StringTableEntry fileName)
    }
    else
    {
-      AssetPtr<ShapeAsset> shapeAsset = shapeAssetId; //ensures the fallback is loaded
+      foundAssetcount = AssetDatabase.findAssetType(&query, "ShapeAsset");
+      if (foundAssetcount != 0)
+      {
+         // loop all image assets and see if we can find one
+         // using the same image file/named target.
+         for (auto shapeAsset : query.mAssetList)
+         {
+            AssetPtr<ShapeAsset> temp = shapeAsset;
+            if (temp.notNull())
+            {
+               if (temp->getShapePath() == fileName)
+               {
+                  return shapeAsset;
+               }
+               else
+               {
+                  Torque::Path temp1 = temp->getShapePath();
+                  Torque::Path temp2 = fileName;
+
+                  if (temp1.getPath() == temp2.getPath() && temp1.getFileName() == temp2.getFileName())
+                  {
+                     return shapeAsset;
+                  }
+               }
+
+            }
+         }
+      }
+      else
+      {
+         AssetPtr<ShapeAsset> shapeAsset = shapeAssetId; //ensures the fallback is loaded
+      }
    }
 
    return shapeAssetId;

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

@@ -212,6 +212,9 @@ protected:
 DefineConsoleType(TypeShapeAssetPtr, S32)
 DefineConsoleType(TypeShapeAssetId, String)
 
+DECLARE_STRUCT(AssetPtr<ShapeAsset>)
+DefineConsoleType(TypeShapeAssetPtrRefactor, AssetPtr<ShapeAsset>)
+
 #ifdef TORQUE_TOOLS
 //-----------------------------------------------------------------------------
 // TypeAssetId GuiInspectorField Class
@@ -493,4 +496,196 @@ public: \
 
 #pragma endregion
 
+
+//-----------------------------------------------------------------------------
+// REFACTOR
+//-----------------------------------------------------------------------------
+
+#pragma region Refactor Asset Macros
+
+#define DECLARE_SHAPEASSET_REFACTOR(className, name)                                                                                                                          \
+private:                                                                                                                                                                      \
+   AssetPtr<ShapeAsset> m##name##Asset;                                                                                                                                       \
+   StringTableEntry     m##name##File = StringTable->EmptyString();                                                                                                           \
+public:                                                                                                                                                                       \
+   void _set##name(StringTableEntry _in) {                                                                                                                                    \
+      if (m##name##Asset.getAssetId() == _in)                                                                                                                                 \
+         return;                                                                                                                                                              \
+      if(get##name##File() == _in)                                                                                                                                            \
+         return;                                                                                                                                                              \
+      if (_in == NULL || _in == StringTable->EmptyString())                                                                                                                   \
+      {                                                                                                                                                                       \
+         m##name##Asset = NULL;                                                                                                                                               \
+         m##name##File = "";                                                                                                                                                  \
+         return;                                                                                                                                                              \
+      }                                                                                                                                                                       \
+      if (!AssetDatabase.isDeclaredAsset(_in))                                                                                                                                \
+      {                                                                                                                                                                       \
+         StringTableEntry shapeAssetId = StringTable->EmptyString();                                                                                                          \
+         AssetQuery query;                                                                                                                                                    \
+         S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in);                                                                                                 \
+         if (foundAssetcount != 0)                                                                                                                                            \
+         {                                                                                                                                                                    \
+            shapeAssetId = query.mAssetList[0];                                                                                                                               \
+         }                                                                                                                                                                    \
+         else if (Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#'))                                                                                                \
+         {                                                                                                                                                                    \
+            shapeAssetId = ShapeAsset::getAssetIdByFilename(_in);                                                                                                             \
+            if (shapeAssetId == ShapeAsset::smNoShapeAssetFallback)                                                                                                           \
+            {                                                                                                                                                                 \
+               ShapeAsset* privateShape = new ShapeAsset();                                                                                                                   \
+               privateShape->setShapeFile(_in);                                                                                                                               \
+               shapeAssetId = AssetDatabase.addPrivateAsset(privateShape);                                                                                                    \
+            }                                                                                                                                                                 \
+         }                                                                                                                                                                    \
+         else                                                                                                                                                                 \
+         {                                                                                                                                                                    \
+            Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in);                                                                        \
+            shapeAssetId = ShapeAsset::smNoShapeAssetFallback;                                                                                                                \
+         }                                                                                                                                                                    \
+         m##name##Asset = shapeAssetId;                                                                                                                                       \
+         m##name##File = _in;                                                                                                                                                 \
+      }                                                                                                                                                                       \
+      else                                                                                                                                                                    \
+      {                                                                                                                                                                       \
+         m##name##Asset = _in;                                                                                                                                                \
+         m##name##File = get##name##File();                                                                                                                                   \
+      }                                                                                                                                                                       \
+   };                                                                                                                                                                         \
+                                                                                                                                                                              \
+   inline StringTableEntry _get##name##AssetId(void) const { return m##name##Asset.getAssetId(); }                                                                            \
+   Resource<TSShape> get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return NULL; }                                               \
+   AssetPtr<ShapeAsset> get##name##Asset(void) { return m##name##Asset; }                                                                                                     \
+   static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast<className*>(obj)->_set##name(_getStringTable()->insert(data)); return false; }  \
+   StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; }
+
+#define DECLARE_SHAPEASSET_NET_REFACTOR(className, name, mask)                                                                                                                \
+private:                                                                                                                                                                      \
+   AssetPtr<ShapeAsset> m##name##Asset;                                                                                                                                       \
+   StringTableEntry     m##name##File = StringTable->EmptyString();                                                                                                           \
+public:                                                                                                                                                                       \
+   void _set##name(StringTableEntry _in) {                                                                                                                                    \
+      if (m##name##Asset.getAssetId() == _in)                                                                                                                                 \
+         return;                                                                                                                                                              \
+      if(get##name##File() == _in)                                                                                                                                            \
+         return;                                                                                                                                                              \
+      if (_in == NULL || _in == StringTable->EmptyString())                                                                                                                   \
+      {                                                                                                                                                                       \
+         m##name##Asset = NULL;                                                                                                                                               \
+         m##name##File = "";                                                                                                                                                  \
+         setMaskBits(mask);                                                                                                                                                   \
+         return;                                                                                                                                                              \
+      }                                                                                                                                                                       \
+      if (!AssetDatabase.isDeclaredAsset(_in))                                                                                                                                \
+      {                                                                                                                                                                       \
+         StringTableEntry shapeAssetId = StringTable->EmptyString();                                                                                                          \
+         AssetQuery query;                                                                                                                                                    \
+         S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in);                                                                                                 \
+         if (foundAssetcount != 0)                                                                                                                                            \
+         {                                                                                                                                                                    \
+            shapeAssetId = query.mAssetList[0];                                                                                                                               \
+         }                                                                                                                                                                    \
+         else if (Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#'))                                                                                                \
+         {                                                                                                                                                                    \
+            shapeAssetId = ShapeAsset::getAssetIdByFilename(_in);                                                                                                             \
+            if (shapeAssetId == ShapeAsset::smNoShapeAssetFallback)                                                                                                           \
+            {                                                                                                                                                                 \
+               ShapeAsset* privateShape = new ShapeAsset();                                                                                                                   \
+               privateShape->setShapeFile(_in);                                                                                                                               \
+               shapeAssetId = AssetDatabase.addPrivateAsset(privateShape);                                                                                                    \
+            }                                                                                                                                                                 \
+         }                                                                                                                                                                    \
+         else                                                                                                                                                                 \
+         {                                                                                                                                                                    \
+            Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in);                                                                        \
+            shapeAssetId = ShapeAsset::smNoShapeAssetFallback;                                                                                                                \
+         }                                                                                                                                                                    \
+         m##name##Asset = shapeAssetId;                                                                                                                                       \
+         m##name##File = _in;                                                                                                                                                 \
+      }                                                                                                                                                                       \
+      else                                                                                                                                                                    \
+      {                                                                                                                                                                       \
+         m##name##Asset = _in;                                                                                                                                                \
+         m##name##File = get##name##File();                                                                                                                                   \
+      }                                                                                                                                                                       \
+      setMaskBits(mask);                                                                                                                                                      \
+   };                                                                                                                                                                         \
+                                                                                                                                                                              \
+   inline StringTableEntry _get##name##AssetId(void) const { return m##name##Asset.getAssetId(); }                                                                            \
+   Resource<TSShape> get##name() { if (m##name##Asset.notNull()) return m##name##Asset->getShapeResource(); else return NULL; }                                               \
+   AssetPtr<ShapeAsset> get##name##Asset(void) { return m##name##Asset; }                                                                                                     \
+   static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast<className*>(obj)->_set##name(_getStringTable()->insert(data)); return false; }  \
+   StringTableEntry get##name##File() { return m##name##Asset.notNull() ? m##name##Asset->getShapePath() : ""; }  
+
+#define INITPERSISTFIELD_SHAPEASSET_REFACTOR(name, consoleClass, docs)                                                                                                                \
+   addProtectedField(assetText(name, Asset), TypeShapeAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); \
+   addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, file docs.));
+
+
+#define DECLARE_SHAPEASSET_ARRAY_REFACTOR(className, name, max)                                                                                                               \
+private:                                                                                                                                                                      \
+   AssetPtr<ShapeAsset> m##name##Asset[max];                                                                                                                                  \
+   StringTableEntry     m##name##File[max] = {StringTable->EmptyString() };                                                                                                   \
+public:                                                                                                                                                                       \
+   void _set##name(StringTableEntry _in, const U32& index){                                                                                                                   \
+      if (m##name##Asset[index].getAssetId() == _in)                                                                                                                          \
+         return;                                                                                                                                                              \
+      if(get##name##File(index) == _in)                                                                                                                                       \
+         return;                                                                                                                                                              \
+      if (_in == NULL || _in == StringTable->EmptyString())                                                                                                                   \
+      {                                                                                                                                                                       \
+         m##name##Asset[index] = NULL;                                                                                                                                        \
+         m##name##File[index] = "";                                                                                                                                           \
+         return;                                                                                                                                                              \
+      }                                                                                                                                                                       \
+      if (!AssetDatabase.isDeclaredAsset(_in))                                                                                                                                \
+      {                                                                                                                                                                       \
+         StringTableEntry shapeAssetId = StringTable->EmptyString();                                                                                                          \
+         AssetQuery query;                                                                                                                                                    \
+         S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, _in);                                                                                                 \
+         if (foundAssetcount != 0)                                                                                                                                            \
+         {                                                                                                                                                                    \
+            shapeAssetId = query.mAssetList[0];                                                                                                                               \
+         }                                                                                                                                                                    \
+         else if (Torque::FS::IsFile(_in) || (_in[0] == '$' || _in[0] == '#'))                                                                                                \
+         {                                                                                                                                                                    \
+            shapeAssetId = ShapeAsset::getAssetIdByFilename(_in);                                                                                                             \
+            if (shapeAssetId == ShapeAsset::smNoShapeAssetFallback)                                                                                                           \
+            {                                                                                                                                                                 \
+               ShapeAsset* privateShape = new ShapeAsset();                                                                                                                   \
+               privateShape->setShapeFile(_in);                                                                                                                               \
+               shapeAssetId = AssetDatabase.addPrivateAsset(privateShape);                                                                                                    \
+            }                                                                                                                                                                 \
+         }                                                                                                                                                                    \
+         else                                                                                                                                                                 \
+         {                                                                                                                                                                    \
+            Con::warnf("%s::%s: Could not find asset for: %s using fallback", #className, #name, _in);                                                                        \
+            shapeAssetId = ShapeAsset::smNoShapeAssetFallback;                                                                                                                \
+         }                                                                                                                                                                    \
+         m##name##Asset[index] = shapeAssetId;                                                                                                                                \
+         m##name##File[index] = _in;                                                                                                                                          \
+      }                                                                                                                                                                       \
+      else                                                                                                                                                                    \
+      {                                                                                                                                                                       \
+         m##name##Asset[index] = _in;                                                                                                                                         \
+         m##name##File[index] = get##name##File(index);                                                                                                                       \
+      }                                                                                                                                                                       \
+   };                                                                                                                                                                         \
+                                                                                                                                                                              \
+   inline StringTableEntry _get##name##AssetId(const U32& index) const { return m##name##Asset[index].getAssetId(); }                                                         \
+   Resource<TSShape> get##name(const U32& index) { if (m##name##Asset[index].notNull()) return m##name##Asset[index]->getShapeResource(); else return NULL; }                 \
+   AssetPtr<ShapeAsset> get##name##Asset(const U32& index) { return m##name##Asset[index]; }                                                                                  \
+   static bool _set##name##Data(void* obj, const char* index, const char* data) { static_cast<className*>(obj)->_set##name(_getStringTable()->insert(data), dAtoi(index)); return false;}\
+   StringTableEntry get##name##File(const U32& idx) { return m##name##Asset[idx].notNull() ? m##name##Asset[idx]->getShapePath() : ""; }
+
+#define INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(name, arraySize, consoleClass, docs)                                                                                       \
+   addProtectedField(assetText(name, Asset), TypeShapeAssetPtrRefactor, Offset(m##name##Asset, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));\
+   addProtectedField(assetText(name, File), TypeFilename, Offset(m##name##File, consoleClass), _set##name##Data, &defaultProtectedGetFn, arraySize, assetDoc(name, asset docs.));
+
+#pragma endregion
+
+//-----------------------------------------------------------------------------
+// REFACTOR END
+//-----------------------------------------------------------------------------
+
 #endif

+ 14 - 14
Engine/source/T3D/debris.cpp

@@ -116,7 +116,7 @@ DebrisData::DebrisData()
    terminalVelocity = 0.0f;
    ignoreWater = true;
 
-   INIT_ASSET(Shape);
+   mShapeAsset.registerRefreshNotify(this);
 }
 
 //#define TRACK_DEBRIS_DATA_CLONES
@@ -152,7 +152,7 @@ DebrisData::DebrisData(const DebrisData& other, bool temp_clone) : GameBaseData(
    terminalVelocity = other.terminalVelocity;
    ignoreWater = other.ignoreWater;
 
-   CLONE_ASSET(Shape);
+   mShapeAsset = other.mShapeAsset;
 
    textureName = other.textureName;
    explosionId = other.explosionId; // -- for pack/unpack of explosion ptr
@@ -191,7 +191,7 @@ DebrisData* DebrisData::cloneAndPerformSubstitutions(const SimObject* owner, S32
 
 void DebrisData::onPerformSubstitutions() 
 { 
-   _setShape(getShape());
+   _setShape(_getShapeAssetId());
 }
 
 bool DebrisData::onAdd()
@@ -276,16 +276,16 @@ bool DebrisData::preload(bool server, String &errorStr)
 
    if (mShapeAsset.notNull())
    {
-      if (!mShape)
+      if (!getShape())
       {
-         errorStr = String::ToString("DebrisData::load: Couldn't load shape \"%s\"", mShapeAssetId);
+         errorStr = String::ToString("DebrisData::load: Couldn't load shape \"%s\"", _getShapeAssetId());
          return false;
       }
       else
       {
-         TSShapeInstance* pDummy = new TSShapeInstance(mShape, !server);
+         TSShapeInstance* pDummy = new TSShapeInstance(getShape(), !server);
          delete pDummy;
-         if (!server && !mShape->preloadMaterialList(mShape.getPath()) && NetConnection::filesWereDownloaded())
+         if (!server && !getShape()->preloadMaterialList(getShape().getPath()) && NetConnection::filesWereDownloaded())
             return false;
       }
    }
@@ -304,7 +304,7 @@ void DebrisData::initPersistFields()
    addGroup("Shapes");
       addField("texture",              TypeString,                  Offset(textureName,         DebrisData), 
          "@brief Texture imagemap to use for this debris object.\n\nNot used any more.\n", AbstractClassRep::FIELD_HideInInspectors);
-      INITPERSISTFIELD_SHAPEASSET(Shape, DebrisData, "Shape to use for this debris object.");
+      INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, DebrisData, "Shape to use for this debris object.");
    endGroup("Shapes");
 
    addGroup("Particle Effects");
@@ -389,7 +389,7 @@ void DebrisData::packData(BitStream* stream)
 
    stream->writeString( textureName );
 
-   PACKDATA_ASSET(Shape);
+   PACKDATA_ASSET_REFACTOR(Shape);
 
    for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
    {
@@ -433,7 +433,7 @@ void DebrisData::unpackData(BitStream* stream)
 
    textureName = stream->readSTString();
 
-   UNPACKDATA_ASSET(Shape);
+   UNPACKDATA_ASSET_REFACTOR(Shape);
 
    for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
    {
@@ -676,18 +676,18 @@ bool Debris::onAdd()
    mFriction = mDataBlock->friction;
 
    // Setup our bounding box
-   if( mDataBlock->mShape )
+   if( mDataBlock->getShape())
    {
-      mObjBox = mDataBlock->mShape->mBounds;
+      mObjBox = mDataBlock->getShape()->mBounds;
    }
    else
    {
       mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
    }
 
-   if( mDataBlock->mShape)
+   if( mDataBlock->getShape())
    {
-      mShape = new TSShapeInstance( mDataBlock->mShape, true);
+      mShape = new TSShapeInstance( mDataBlock->getShape(), true);
    }
 
    if( mPart )

+ 4 - 4
Engine/source/T3D/debris.h

@@ -47,7 +47,7 @@ class TSShape;
 //**************************************************************************
 // Debris Data
 //**************************************************************************
-struct DebrisData : public GameBaseData
+struct DebrisData : public GameBaseData, protected AssetPtrCallback
 {
    typedef GameBaseData Parent;
 
@@ -83,8 +83,7 @@ struct DebrisData : public GameBaseData
    F32      terminalVelocity;    // max velocity magnitude
    bool     ignoreWater;
 
-   DECLARE_SHAPEASSET(DebrisData, Shape, onShapeChanged);
-   DECLARE_ASSET_SETGET(DebrisData, Shape);
+   DECLARE_SHAPEASSET_REFACTOR(DebrisData, Shape)
 
    StringTableEntry  textureName;
 
@@ -111,7 +110,8 @@ public:
    void onPerformSubstitutions() override;
    bool allowSubstitutions() const override { return true; }
 
-   void onShapeChanged()
+protected:
+   void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override
    {
       reloadOnLocalClient();
    }

+ 7 - 12
Engine/source/T3D/examples/renderShapeExample.cpp

@@ -59,7 +59,6 @@ RenderShapeExample::RenderShapeExample()
    mTypeMask |= StaticObjectType | StaticShapeObjectType;
 
    // Make sure to initialize our TSShapeInstance to NULL
-   INIT_ASSET(Shape);
    mShapeInstance = NULL;
 }
 
@@ -75,7 +74,7 @@ void RenderShapeExample::initPersistFields()
    docsURL;
    Parent::initPersistFields();
    addGroup( "Shapes" );
-   INITPERSISTFIELD_SHAPEASSET(Shape, RenderShapeExample, "The path to the shape file.")
+   INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, RenderShapeExample, "The path to the shape file.")
    endGroup( "Shapes" );
 
    // SceneObject already handles exposing the transform
@@ -147,7 +146,7 @@ U32 RenderShapeExample::packUpdate( NetConnection *conn, U32 mask, BitStream *st
    // Write out any of the updated editable properties
    if ( stream->writeFlag( mask & UpdateMask ) )
    {
-      PACK_ASSET(conn, Shape);
+      PACK_ASSET_REFACTOR(conn, Shape);
 
       // Allow the server object a chance to handle a new shape
       createShape();
@@ -171,7 +170,7 @@ void RenderShapeExample::unpackUpdate(NetConnection *conn, BitStream *stream)
 
    if ( stream->readFlag() )  // UpdateMask
    {
-      UNPACK_ASSET(conn, Shape);
+      UNPACK_ASSET_REFACTOR(conn, Shape);
 
       if ( isProperlyAdded() )
          createShape();
@@ -183,11 +182,7 @@ void RenderShapeExample::unpackUpdate(NetConnection *conn, BitStream *stream)
 //-----------------------------------------------------------------------------
 void RenderShapeExample::createShape()
 {
-   if ( getShape() == StringTable->EmptyString() )
-      return;
-
-   // If this is the same shape then no reason to update it
-   if ( mShapeInstance && getShape() == StringTable->insert(mShape.getPath().getFullPath().c_str()) )
+   if ( mShapeAsset.isNull() )
       return;
 
    // Clean up our previous shape
@@ -196,19 +191,19 @@ void RenderShapeExample::createShape()
 
    // Attempt to preload the Materials for this shape
    if ( isClientObject() && 
-        !mShape->preloadMaterialList( mShape.getPath() ) && 
+        !getShape()->preloadMaterialList(getShape().getPath() ) &&
         NetConnection::filesWereDownloaded() )
    {
       return;
    }
 
    // Update the bounding box
-   mObjBox = mShape->mBounds;
+   mObjBox = getShape()->mBounds;
    resetWorldBox();
    setRenderTransform(mObjToWorld);
 
    // Create the TSShapeInstance
-   mShapeInstance = new TSShapeInstance( mShape, isClientObject() );
+   mShapeInstance = new TSShapeInstance(getShape(), isClientObject() );
 }
 
 void RenderShapeExample::prepRenderImage( SceneRenderState *state )

+ 2 - 5
Engine/source/T3D/examples/renderShapeExample.h

@@ -61,14 +61,11 @@ class RenderShapeExample : public SceneObject
    //--------------------------------------------------------------------------
    // Rendering variables
    //--------------------------------------------------------------------------
-   DECLARE_SHAPEASSET(RenderShapeExample, Shape, onShapeChanged);
-   DECLARE_ASSET_SETGET(RenderShapeExample, Shape);
+   DECLARE_SHAPEASSET_REFACTOR(RenderShapeExample, Shape)
 
    // The actual shape instance
    TSShapeInstance*  mShapeInstance;
 
-   void onShapeChanged() {}
-
 public:
    RenderShapeExample();
    virtual ~RenderShapeExample();
@@ -119,4 +116,4 @@ public:
    void prepRenderImage( SceneRenderState *state ) override;
 };
 
-#endif // _RENDERSHAPEEXAMPLE_H_
+#endif // _RENDERSHAPEEXAMPLE_H_

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

@@ -444,14 +444,14 @@ void SpawnSphere::unpackUpdate(NetConnection * con, BitStream * stream)
       {
          delete mShapeInstance;
          ShapeBaseData *spawnedDatablock = dynamic_cast<ShapeBaseData *>(Sim::findObject(mSpawnDataBlock.c_str()));
-         if (spawnedDatablock && spawnedDatablock->mShape)
+         if (spawnedDatablock && spawnedDatablock->getShape())
          {
-               mShapeInstance = new TSShapeInstance(spawnedDatablock->mShape);
+               mShapeInstance = new TSShapeInstance(spawnedDatablock->getShape());
          }
          else if (mDataBlock)
          {
-            if (mDataBlock->mShape)
-               mShapeInstance = new TSShapeInstance(mDataBlock->mShape);
+            if (mDataBlock->getShape())
+               mShapeInstance = new TSShapeInstance(mDataBlock->getShape());
          }
       }
       stream->read(&mSpawnName);

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

@@ -502,10 +502,10 @@ bool PlayerData::preload(bool server, String &errorStr)
 
    // If we don't have a shape don't crash out trying to
    // setup animations and sequences.
-   if ( mShape )
+   if (getShape())
    {
       // Go ahead a pre-load the player shape
-      TSShapeInstance* si = new TSShapeInstance(mShape, false);
+      TSShapeInstance* si = new TSShapeInstance(getShape(), false);
       TSThread* thread = si->addThread();
 
       // Extract ground transform velocity from animations
@@ -516,7 +516,7 @@ bool PlayerData::preload(bool server, String &errorStr)
          ActionAnimationDef *sp = &ActionAnimationList[i];
          dp->name          = sp->name;
          dp->dir.set(sp->dir.x,sp->dir.y,sp->dir.z);
-         dp->sequence      = mShape->findSequence(sp->name);
+         dp->sequence      = getShape()->findSequence(sp->name);
 
          // If this is a sprint action and is missing a sequence, attempt to use
          // the standard run ones.
@@ -524,7 +524,7 @@ bool PlayerData::preload(bool server, String &errorStr)
          {
             S32 offset = i-SprintRootAnim;
             ActionAnimationDef *standDef = &ActionAnimationList[RootAnim+offset];
-            dp->sequence = mShape->findSequence(standDef->name);
+            dp->sequence = getShape()->findSequence(standDef->name);
          }
 
          dp->velocityScale = true;
@@ -532,12 +532,12 @@ bool PlayerData::preload(bool server, String &errorStr)
          if (dp->sequence != -1)
             getGroundInfo(si,thread,dp);
       }
-      for (S32 b = 0; b < mShape->sequences.size(); b++)
+      for (S32 b = 0; b < getShape()->sequences.size(); b++)
       {
          if (!isTableSequence(b))
          {
             dp->sequence      = b;
-            dp->name          = mShape->getName(mShape->sequences[b].nameIndex);
+            dp->name          = getShape()->getName(getShape()->sequences[b].nameIndex);
             dp->velocityScale = false;
             getGroundInfo(si,thread,dp++);
          }
@@ -554,17 +554,17 @@ bool PlayerData::preload(bool server, String &errorStr)
             lookAction = c;
 
       // Resolve spine
-      spineNode[0] = mShape->findNode("Bip01 Pelvis");
-      spineNode[1] = mShape->findNode("Bip01 Spine");
-      spineNode[2] = mShape->findNode("Bip01 Spine1");
-      spineNode[3] = mShape->findNode("Bip01 Spine2");
-      spineNode[4] = mShape->findNode("Bip01 Neck");
-      spineNode[5] = mShape->findNode("Bip01 Head");
+      spineNode[0] = getShape()->findNode("Bip01 Pelvis");
+      spineNode[1] = getShape()->findNode("Bip01 Spine");
+      spineNode[2] = getShape()->findNode("Bip01 Spine1");
+      spineNode[3] = getShape()->findNode("Bip01 Spine2");
+      spineNode[4] = getShape()->findNode("Bip01 Neck");
+      spineNode[5] = getShape()->findNode("Bip01 Head");
 
       // Recoil animations
-      recoilSequence[0] = mShape->findSequence("light_recoil");
-      recoilSequence[1] = mShape->findSequence("medium_recoil");
-      recoilSequence[2] = mShape->findSequence("heavy_recoil");
+      recoilSequence[0] = getShape()->findSequence("light_recoil");
+      recoilSequence[1] = getShape()->findSequence("medium_recoil");
+      recoilSequence[2] = getShape()->findSequence("heavy_recoil");
    }
 
    // Convert pickupRadius to a delta of boundingBox
@@ -7511,8 +7511,8 @@ F32 Player::getAnimationDurationByID(U32 anim_id)
    if (anim_id == BAD_ANIM_ID)
       return 0.0f;
    S32 seq_id = mDataBlock->actionList[anim_id].sequence;
-   if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
-      return mDataBlock->mShape->sequences[seq_id].duration;
+   if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size())
+      return mDataBlock->getShape()->sequences[seq_id].duration;
 
    return 0.0f;
 }
@@ -7524,8 +7524,8 @@ bool Player::isBlendAnimation(const char* name)
       return false;
 
    S32 seq_id = mDataBlock->actionList[anim_id].sequence;
-   if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
-      return mDataBlock->mShape->sequences[seq_id].isBlend();
+   if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size())
+      return mDataBlock->getShape()->sequences[seq_id].isBlend();
 
    return false;
 }

+ 3 - 3
Engine/source/T3D/proximityMine.cpp

@@ -144,11 +144,11 @@ bool ProximityMineData::preload( bool server, String& errorStr )
       }
    }
 
-   if ( mShape )
+   if ( getShape() )
    {
       // Lookup animation sequences
-      armingSequence = mShape->findSequence( "armed" );
-      triggerSequence = mShape->findSequence( "triggered" );
+      armingSequence = getShape()->findSequence( "armed" );
+      triggerSequence = getShape()->findSequence( "triggered" );
    }
 
    return true;

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

@@ -310,7 +310,7 @@ bool RigidShapeData::preload(bool server, String &errorStr)
    if (!collisionDetails.size() || collisionDetails[0] == -1)
    {
       Con::errorf("RigidShapeData::preload failed: Rigid shapes must define a collision-1 detail");
-      errorStr = String::ToString("RigidShapeData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId());
+      errorStr = String::ToString("RigidShapeData: Couldn't load shape asset \"%s\"", getShapeAsset().getAssetId());
       return false;
    }
 

+ 152 - 159
Engine/source/T3D/shapeBase.cpp

@@ -201,13 +201,12 @@ ShapeBaseData::ShapeBaseData()
    inheritEnergyFromMount( false ),
    mAIControllData(NULL)
 {
-   INIT_ASSET(Shape);
-   INIT_ASSET(DebrisShape);
-
    dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints );
    remap_txr_tags = NULL;
    remap_buffer = NULL;
    silent_bbox_check = false;
+   mShapeAsset.registerRefreshNotify(this);
+   mDebrisShapeAsset.registerRefreshNotify(this);
 }
 
 ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : GameBaseData(other, temp_clone)
@@ -217,13 +216,13 @@ ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : Game
    shadowProjectionDistance = other.shadowProjectionDistance;
    shadowSphereAdjust = other.shadowSphereAdjust;
    cloakTexName = other.cloakTexName;
-   CLONE_ASSET(Shape);
+   mShapeAsset = other.mShapeAsset;
    cubeDescName = other.cubeDescName;
    cubeDescId = other.cubeDescId;
    reflectorDesc = other.reflectorDesc;
    debris = other.debris;
    debrisID = other.debrisID; // -- for pack/unpack of debris ptr
-   CLONE_ASSET(DebrisShape);
+   mDebrisShapeAsset = other.mDebrisShapeAsset;
    explosion = other.explosion;
    explosionID = other.explosionID; // -- for pack/unpack of explosion ptr
    underwaterExplosion = other.underwaterExplosion;
@@ -245,7 +244,6 @@ ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : Game
    cameraMaxFov = other.cameraMaxFov;
    cameraCanBank = other.cameraCanBank;
    mountedImagesBank = other.mountedImagesBank;
-   mShape = other.mShape; // -- TSShape loaded using shapeName
    mCRC = other.mCRC; // -- from shape, used to verify client shape 
    computeCRC = other.computeCRC;
    eyeNode = other.eyeNode; // -- from shape node "eye"
@@ -304,6 +302,9 @@ ShapeBaseData::~ShapeBaseData()
 
    if (remap_buffer && !isTempClone())
       dFree(remap_buffer);
+
+   mShapeAsset.unregisterRefreshNotify();
+   mDebrisShapeAsset.unregisterRefreshNotify();
 }
 
 bool ShapeBaseData::preload(bool server, String &errorStr)
@@ -342,156 +343,159 @@ bool ShapeBaseData::preload(bool server, String &errorStr)
             "ShapeBaseData::preload: invalid debris data");
       }
 
-      if( bool(mDebrisShape))
+      if(mDebrisShapeAsset.notNull())
       {
-         TSShapeInstance* pDummy = new TSShapeInstance(mDebrisShape, !server);
+         TSShapeInstance* pDummy = new TSShapeInstance(getDebrisShape(), !server);
          delete pDummy;
       }
    }
 
    S32 i;
-   U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset);
-   if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback)
+   if (mShapeAsset.notNull())
    {
-      if (!server && !mShape->preloadMaterialList(mShape.getPath()) && NetConnection::filesWereDownloaded())
-         shapeError = true;
-
-      if(computeCRC)
-      {
-         Con::printf("Validation required for shape asset: %s", mShapeAsset.getAssetId());
-
-         Torque::FS::FileNodeRef    fileRef = Torque::FS::GetFileNode(mShapeAsset->getShapePath());
-
-         if (!fileRef)
-         {
-            errorStr = String::ToString("ShapeBaseData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId());
-            return false;
-         }
-
-         if(server)
-            mCRC = fileRef->getChecksum();
-         else if(mCRC != fileRef->getChecksum())
-         {
-            errorStr = String::ToString("Shape asset \"%s\" does not match version on server.", mShapeAsset.getAssetId());
-            return false;
-         }
-      }
-      // Resolve details and camera node indexes.
-      static const String sCollisionStr( "collision-" );
-
-      for (i = 0; i < mShape->details.size(); i++)
+      U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset);
+      if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback)
       {
-         const String &name = mShape->names[mShape->details[i].nameIndex];
+         if (!server && !getShape()->preloadMaterialList(getShape().getPath()) && NetConnection::filesWereDownloaded())
+            shapeError = true;
 
-         if (name.compare( sCollisionStr, sCollisionStr.length(), String::NoCase ) == 0)
+         if (computeCRC)
          {
-            collisionDetails.push_back(i);
-            collisionBounds.increment();
+            Con::printf("Validation required for shape asset: %s", mShapeAsset.getAssetId());
 
-            mShape->computeBounds(collisionDetails.last(), collisionBounds.last());
-            mShape->getAccelerator(collisionDetails.last());
+            Torque::FS::FileNodeRef    fileRef = Torque::FS::GetFileNode(mShapeAsset->getShapePath());
 
-            if (!mShape->mBounds.isContained(collisionBounds.last()))
+            if (!fileRef)
             {
-               if (!silent_bbox_check)
-               Con::warnf("Warning: shape asset %s collision detail %d (Collision-%d) bounds exceed that of shape.", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last());
-               collisionBounds.last() = mShape->mBounds;
+               errorStr = String::ToString("ShapeBaseData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId());
+               return false;
             }
-            else if (collisionBounds.last().isValidBox() == false)
+
+            if (server)
+               mCRC = fileRef->getChecksum();
+            else if (mCRC != fileRef->getChecksum())
             {
-               if (!silent_bbox_check)
-               Con::errorf("Error: shape asset %s-collision detail %d (Collision-%d) bounds box invalid!", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last());
-               collisionBounds.last() = mShape->mBounds;
+               errorStr = String::ToString("Shape asset \"%s\" does not match version on server.", mShapeAsset.getAssetId());
+               return false;
             }
+         }
+         // Resolve details and camera node indexes.
+         static const String sCollisionStr("collision-");
 
-            // The way LOS works is that it will check to see if there is a LOS detail that matches
-            // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in
-            // the future). If it can't find a matching LOS it will simply use the collision instead.
-            // We check for any "unmatched" LOS's further down
-            LOSDetails.increment();
+         for (i = 0; i < getShape()->details.size(); i++)
+         {
+            const String& name = getShape()->names[getShape()->details[i].nameIndex];
 
-            String   buff = String::ToString("LOS-%d", i + 1 + MaxCollisionShapes);
-            U32 los = mShape->findDetail(buff);
-            if (los == -1)
-               LOSDetails.last() = i;
-            else
-               LOSDetails.last() = los;
-         }
-      }
+            if (name.compare(sCollisionStr, sCollisionStr.length(), String::NoCase) == 0)
+            {
+               collisionDetails.push_back(i);
+               collisionBounds.increment();
 
-      // Snag any "unmatched" LOS details
-      static const String sLOSStr( "LOS-" );
+               getShape()->computeBounds(collisionDetails.last(), collisionBounds.last());
+               getShape()->getAccelerator(collisionDetails.last());
 
-      for (i = 0; i < mShape->details.size(); i++)
-      {
-         const String &name = mShape->names[mShape->details[i].nameIndex];
+               if (!getShape()->mBounds.isContained(collisionBounds.last()))
+               {
+                  if (!silent_bbox_check)
+                     Con::warnf("Warning: shape asset %s collision detail %d (Collision-%d) bounds exceed that of shape.", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last());
+                  collisionBounds.last() = getShape()->mBounds;
+               }
+               else if (collisionBounds.last().isValidBox() == false)
+               {
+                  if (!silent_bbox_check)
+                     Con::errorf("Error: shape asset %s-collision detail %d (Collision-%d) bounds box invalid!", mShapeAsset.getAssetId(), collisionDetails.size() - 1, collisionDetails.last());
+                  collisionBounds.last() = getShape()->mBounds;
+               }
 
-         if (name.compare( sLOSStr, sLOSStr.length(), String::NoCase ) == 0)
+               // The way LOS works is that it will check to see if there is a LOS detail that matches
+               // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in
+               // the future). If it can't find a matching LOS it will simply use the collision instead.
+               // We check for any "unmatched" LOS's further down
+               LOSDetails.increment();
+
+               String   buff = String::ToString("LOS-%d", i + 1 + MaxCollisionShapes);
+               U32 los = getShape()->findDetail(buff);
+               if (los == -1)
+                  LOSDetails.last() = i;
+               else
+                  LOSDetails.last() = los;
+            }
+         }
+
+         // Snag any "unmatched" LOS details
+         static const String sLOSStr("LOS-");
+
+         for (i = 0; i < getShape()->details.size(); i++)
          {
-            // See if we already have this LOS
-            bool found = false;
-            for (U32 j = 0; j < LOSDetails.size(); j++)
+            const String& name = getShape()->names[getShape()->details[i].nameIndex];
+
+            if (name.compare(sLOSStr, sLOSStr.length(), String::NoCase) == 0)
             {
-               if (LOSDetails[j] == i)
+               // See if we already have this LOS
+               bool found = false;
+               for (U32 j = 0; j < LOSDetails.size(); j++)
                {
+                  if (LOSDetails[j] == i)
+                  {
                      found = true;
                      break;
+                  }
                }
-            }
 
-            if (!found)
-               LOSDetails.push_back(i);
+               if (!found)
+                  LOSDetails.push_back(i);
+            }
          }
-      }
 
-      debrisDetail = mShape->findDetail("Debris-17");
-      eyeNode = mShape->findNode("eye");
-      earNode = mShape->findNode( "ear" );
-      if( earNode == -1 )
-         earNode = eyeNode;
-      cameraNode = mShape->findNode("cam");
-      if (cameraNode == -1)
-         cameraNode = eyeNode;
-
-      // Resolve mount point node indexes
-      for (i = 0; i < SceneObject::NumMountPoints; i++) {
-         char fullName[256];
-         dSprintf(fullName,sizeof(fullName),"mount%d",i);
-         mountPointNode[i] = mShape->findNode(fullName);
-      }
+         debrisDetail = getShape()->findDetail("Debris-17");
+         eyeNode = getShape()->findNode("eye");
+         earNode = getShape()->findNode("ear");
+         if (earNode == -1)
+            earNode = eyeNode;
+         cameraNode = getShape()->findNode("cam");
+         if (cameraNode == -1)
+            cameraNode = eyeNode;
+
+         // Resolve mount point node indexes
+         for (i = 0; i < SceneObject::NumMountPoints; i++) {
+            char fullName[256];
+            dSprintf(fullName, sizeof(fullName), "mount%d", i);
+            mountPointNode[i] = getShape()->findNode(fullName);
+         }
 
-        // find the AIRepairNode - hardcoded to be the last node in the array...
-      mountPointNode[AIRepairNode] = mShape->findNode("AIRepairNode");
+         // find the AIRepairNode - hardcoded to be the last node in the array...
+         mountPointNode[AIRepairNode] = getShape()->findNode("AIRepairNode");
 
-      //
-      hulkSequence = mShape->findSequence("Visibility");
-      damageSequence = mShape->findSequence("Damage");
+         //
+         hulkSequence = getShape()->findSequence("Visibility");
+         damageSequence = getShape()->findSequence("Damage");
 
-      //
-      F32 w = mShape->mBounds.len_y() / 2;
-      if (cameraMaxDist < w)
-         cameraMaxDist = w;
-      // just parse up the string and collect the remappings in txr_tag_remappings.
-      if (!server && remap_txr_tags != NULL && remap_txr_tags != StringTable->insert(""))
-      {
-         txr_tag_remappings.clear();
-         if (remap_buffer)
-            dFree(remap_buffer);
+         //
+         F32 w = getShape()->mBounds.len_y() / 2;
+         if (cameraMaxDist < w)
+            cameraMaxDist = w;
+         // just parse up the string and collect the remappings in txr_tag_remappings.
+         if (!server && remap_txr_tags != NULL && remap_txr_tags != StringTable->insert(""))
+         {
+            txr_tag_remappings.clear();
+            if (remap_buffer)
+               dFree(remap_buffer);
 
-         remap_buffer = dStrdup(remap_txr_tags);
+            remap_buffer = dStrdup(remap_txr_tags);
 
-         char* remap_token = dStrtok(remap_buffer, " \t");
-         while (remap_token != NULL)
-         {
-            char* colon = dStrchr(remap_token, ':');
-            if (colon)
+            char* remap_token = dStrtok(remap_buffer, " \t");
+            while (remap_token != NULL)
             {
-               *colon = '\0';
-               txr_tag_remappings.increment();
-               txr_tag_remappings.last().old_tag = remap_token;
-               txr_tag_remappings.last().new_tag = colon+1;
+               char* colon = dStrchr(remap_token, ':');
+               if (colon)
+               {
+                  *colon = '\0';
+                  txr_tag_remappings.increment();
+                  txr_tag_remappings.last().old_tag = remap_token;
+                  txr_tag_remappings.last().new_tag = colon + 1;
+               }
+               remap_token = dStrtok(NULL, " \t");
             }
-            remap_token = dStrtok(NULL, " \t");
          }
       }
    }
@@ -543,12 +547,12 @@ void ShapeBaseData::initPersistFields()
 {
    docsURL;
    addGroup( "Shapes" );
-      INITPERSISTFIELD_SHAPEASSET(Shape, ShapeBaseData, "The source shape asset.");
+   INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, ShapeBaseData, "The source shape asset.");
       addField("computeCRC", TypeBool, Offset(computeCRC, ShapeBaseData),
          "If true, verify that the CRC of the client's shape model matches the "
          "server's CRC for the shape model when loaded by the client.");
       addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData));
-      INITPERSISTFIELD_SHAPEASSET(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional.");
+      INITPERSISTFIELD_SHAPEASSET_REFACTOR(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional.");
    endGroup( "Shapes" );
    addGroup("Movement");
       addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, ShapeBaseData),
@@ -677,12 +681,12 @@ DefineEngineMethod( ShapeBaseData, checkDeployPos, bool, ( TransformF txfm ),,
 
    "@note This is a server side only check, and is not actually limited to spawning.\n")
 {
-   if (bool(object->mShape) == false)
+   if (bool(object->getShape()) == false)
       return false;
 
    MatrixF mat = txfm.getMatrix();
 
-   Box3F objBox = object->mShape->mBounds;
+   Box3F objBox = object->getShape()->mBounds;
    Point3F boxCenter = (objBox.minExtents + objBox.maxExtents) * 0.5f;
    objBox.minExtents = boxCenter + (objBox.minExtents - boxCenter) * 0.9f;
    objBox.maxExtents = boxCenter + (objBox.maxExtents - boxCenter) * 0.9f;
@@ -752,8 +756,8 @@ void ShapeBaseData::packData(BitStream* stream)
    stream->write(shadowProjectionDistance);
    stream->write(shadowSphereAdjust);
 
-   PACKDATA_ASSET(Shape);
-   PACKDATA_ASSET(DebrisShape);
+   PACKDATA_ASSET_REFACTOR(Shape);
+   PACKDATA_ASSET_REFACTOR(DebrisShape);
 
    stream->writeString(cloakTexName);
    if(stream->writeFlag(mass != gShapeBaseDataProto.mass))
@@ -829,8 +833,8 @@ void ShapeBaseData::unpackData(BitStream* stream)
    stream->read(&shadowProjectionDistance);
    stream->read(&shadowSphereAdjust);
 
-   UNPACKDATA_ASSET(Shape);
-   UNPACKDATA_ASSET(DebrisShape);
+   UNPACKDATA_ASSET_REFACTOR(Shape);
+   UNPACKDATA_ASSET_REFACTOR(DebrisShape);
 
    cloakTexName = stream->readSTString();
    if(stream->readFlag())
@@ -918,17 +922,6 @@ void ShapeBaseData::unpackData(BitStream* stream)
    silent_bbox_check = stream->readFlag();
 }
 
-//
-//
-void ShapeBaseData::onShapeChanged()
-{
-   reloadOnLocalClient();
-}
-
-void ShapeBaseData::onDebrisChanged()
-{
-   reloadOnLocalClient();
-}
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 
@@ -1210,12 +1203,12 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
 
    // Even if loadShape succeeds, there may not actually be
    // a shape assigned to this object.
-   if (bool(mDataBlock->mShape)) {
+   if (bool(mDataBlock->getShape())) {
       delete mShapeInstance;
       if (isClientObject() && mDataBlock->txr_tag_remappings.size() > 0)
       {
          // temporarily substitute material tags with alternates
-         TSMaterialList* mat_list = mDataBlock->mShape->materialList;
+         TSMaterialList* mat_list = mDataBlock->getShape()->materialList;
          if (mat_list)
          {
             for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++)
@@ -1235,7 +1228,7 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
             }
          }
       }
-      mShapeInstance = new TSShapeInstance(mDataBlock->mShape, isClientObject());
+      mShapeInstance = new TSShapeInstance(mDataBlock->getShape(), isClientObject());
       if (isClientObject())
       {
          mShapeInstance->cloneMaterialList();
@@ -1243,7 +1236,7 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
          // restore the material tags to original form
          if (mDataBlock->txr_tag_remappings.size() > 0)
          {
-            TSMaterialList* mat_list = mDataBlock->mShape->materialList;
+            TSMaterialList* mat_list = mDataBlock->getShape()->materialList;
             if (mat_list)
             {
                for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++)
@@ -1269,11 +1262,11 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
          }
       }
 
-      mObjBox = mDataBlock->mShape->mBounds;
+      mObjBox = mDataBlock->getShape()->mBounds;
       resetWorldBox();
 
       // Set the initial mesh hidden state.
-      mMeshHidden.setSize(mDataBlock->mShape->objects.size());
+      mMeshHidden.setSize(mDataBlock->getShape()->objects.size());
       mMeshHidden.clear();
 
       // Initialize the threads
@@ -1297,11 +1290,11 @@ bool ShapeBase::onNewDataBlock( GameBaseData *dptr, bool reload )
 
             AssertFatal(prevDB != NULL, "ShapeBase::onNewDataBlock - how did you have a sequence playing without a prior datablock?");
 
-            const TSShape* prevShape = prevDB->mShape;
+            const TSShape* prevShape = prevDB->getShape();
             const TSShape::Sequence& prevSeq = prevShape->sequences[st.sequence];
             const String& prevSeqName = prevShape->names[prevSeq.nameIndex];
 
-            st.sequence = mDataBlock->mShape->findSequence(prevSeqName);
+            st.sequence = mDataBlock->getShape()->findSequence(prevSeqName);
 
             if (st.sequence != -1)
             {
@@ -1971,13 +1964,13 @@ void ShapeBase::blowUp()
 
    TSShapeInstance *debShape = NULL;
 
-   if( mDataBlock->mDebrisShape == NULL )
+   if( mDataBlock->getDebrisShape() == NULL)
    {
       return;
    }
    else
    {
-      debShape = new TSShapeInstance( mDataBlock->mDebrisShape, true);
+      debShape = new TSShapeInstance( mDataBlock->getDebrisShape(), true);
    }
 
 
@@ -2049,7 +2042,7 @@ Point3F ShapeBase::getAIRepairPoint()
 //----------------------------------------------------------------------------
 void ShapeBase::getNodeTransform(const char* nodeName, MatrixF* outMat)
 {
-   S32 nodeIDx = mDataBlock->getShapeResource()->findNode(nodeName);
+   S32 nodeIDx = mDataBlock->getShape()->findNode(nodeName);
    const MatrixF& xfm = isMounted() ? mMount.xfm : MatrixF::Identity;
 
    MatrixF nodeTransform(xfm);
@@ -2216,7 +2209,7 @@ void ShapeBase::getNodeTransform(const char* nodeName, const MatrixF& xfm, Matri
    if (!mShapeInstance)
       return;
 
-   S32 nodeIDx = mDataBlock->getShapeResource()->findNode(nodeName);
+   S32 nodeIDx = mDataBlock->getShape()->findNode(nodeName);
 
    MatrixF nodeTransform(xfm);
    const Point3F& scale = getScale();
@@ -5027,7 +5020,7 @@ void ShapeBase::_updateHiddenMeshes()
 
 void ShapeBase::setMeshHidden( const char *meshName, bool forceHidden )
 {
-   setMeshHidden( mDataBlock->mShape->findObject( meshName ), forceHidden );
+   setMeshHidden( mDataBlock->getShape()->findObject(meshName), forceHidden);
 }
 
 void ShapeBase::setMeshHidden( S32 meshIndex, bool forceHidden )
@@ -5096,7 +5089,7 @@ void ShapeBase::dumpMeshVisibility()
    {
       const TSShapeInstance::MeshObjectInstance &mesh = meshes[i];
 
-      const String &meshName = mDataBlock->mShape->getMeshName( i );
+      const String &meshName = mDataBlock->getShape()->getMeshName( i );
 
       Con::printf( "%d - %s - forceHidden = %s, visibility = %f", 
          i,
@@ -5378,8 +5371,8 @@ F32 ShapeBase::getAnimationDurationByID(U32 anim_id)
       return 0.0f;
 
    S32 seq_id = (S32) anim_id;
-   if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
-      return mDataBlock->mShape->sequences[seq_id].duration;
+   if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size())
+      return mDataBlock->getShape()->sequences[seq_id].duration;
 
    return 0.0f;
 }
@@ -5391,8 +5384,8 @@ bool ShapeBase::isBlendAnimation(const char* name)
       return false;
 
    S32 seq_id = (S32) anim_id;
-   if (seq_id >= 0 && seq_id < mDataBlock->mShape->sequences.size())
-      return mDataBlock->mShape->sequences[seq_id].isBlend();
+   if (seq_id >= 0 && seq_id < mDataBlock->getShape()->sequences.size())
+      return mDataBlock->getShape()->sequences[seq_id].isBlend();
 
    return false;
 }
@@ -5404,11 +5397,11 @@ const char* ShapeBase::getLastClipName(U32 clip_tag)
 
    S32 seq_id = (S32) last_anim_id;
 
-   S32 idx = mDataBlock->mShape->sequences[seq_id].nameIndex;
-   if (idx < 0 || idx >= mDataBlock->mShape->names.size())
+   S32 idx = mDataBlock->getShape()->sequences[seq_id].nameIndex;
+   if (idx < 0 || idx >= mDataBlock->getShape()->names.size())
       return 0;
 
-   return mDataBlock->mShape->names[idx];
+   return mDataBlock->getShape()->names[idx];
 }
 
 //

+ 18 - 13
Engine/source/T3D/shapeBase.h

@@ -140,7 +140,8 @@ class ShapeBaseConvex : public Convex
 
 //--------------------------------------------------------------------------
 
-struct ShapeBaseImageData: public GameBaseData {
+struct ShapeBaseImageData: public GameBaseData, protected AssetPtrCallback
+{
   private:
    typedef GameBaseData Parent;
 
@@ -380,11 +381,7 @@ struct ShapeBaseImageData: public GameBaseData {
    F32 scriptAnimTransitionTime;    ///< The amount of time to transition between the previous sequence and new sequence
                                     ///< when the script prefix has changed.
 
-   DECLARE_SHAPEASSET_ARRAY(ShapeBaseImageData, Shape, MaxShapes, onShapeChanged);  ///< Name of shape to render.
-   DECLARE_ASSET_ARRAY_SETGET(ShapeBaseImageData, Shape);
-
-   //DECLARE_SHAPEASSET(ShapeBaseImageData, ShapeFP);  ///< Name of shape to render in first person (optional).
-   //DECLARE_ASSET_SETGET(ShapeBaseImageData, ShapeFP);
+   DECLARE_SHAPEASSET_ARRAY_REFACTOR(ShapeBaseImageData, Shape, MaxShapes)  ///< Name of shape to render.
 
    StringTableEntry  imageAnimPrefix;     ///< Passed along to the mounting shape to modify
                                           ///  animation sequences played in 3rd person. [optional]
@@ -519,6 +516,12 @@ struct ShapeBaseImageData: public GameBaseData {
    DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, S32 slot, F32 dt ) );
    DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, S32 slot, F32 dt ) );
    /// @}
+
+protected:
+   void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override
+   {
+      reloadOnLocalClient();
+   }
 };
 
 typedef ShapeBaseImageData::LightType ShapeBaseImageLightType;
@@ -533,7 +536,7 @@ DefineEnumType( ShapeBaseImageRecoilState );
 
 //--------------------------------------------------------------------------
 /// @nosubgrouping
-struct ShapeBaseData : public GameBaseData {
+struct ShapeBaseData : public GameBaseData, protected AssetPtrCallback {
   private:
    typedef GameBaseData Parent;
    
@@ -553,8 +556,7 @@ public:
    F32 shadowProjectionDistance;
    F32 shadowSphereAdjust;
 
-   DECLARE_SHAPEASSET(ShapeBaseData, Shape, onShapeChanged);
-   DECLARE_ASSET_SETGET(ShapeBaseData, Shape);
+   DECLARE_SHAPEASSET_REFACTOR(ShapeBaseData, Shape)
 
    StringTableEntry  cloakTexName;
 
@@ -570,8 +572,7 @@ public:
    DebrisData *      debris;
    S32               debrisID;
 
-   DECLARE_SHAPEASSET(ShapeBaseData, DebrisShape, onDebrisChanged);
-   DECLARE_ASSET_SETGET(ShapeBaseData, DebrisShape);
+   DECLARE_SHAPEASSET_REFACTOR(ShapeBaseData, DebrisShape)
 
    ExplosionData*    explosion;
    S32               explosionID;
@@ -691,10 +692,14 @@ public:
    Vector<TextureTagRemapping> txr_tag_remappings;
    bool silent_bbox_check;
 
-   void onShapeChanged();
-   void onDebrisChanged();
 public:
    ShapeBaseData(const ShapeBaseData&, bool = false);
+
+protected:
+   void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override
+   {
+      reloadOnLocalClient();
+   }
 };
 
 

+ 23 - 33
Engine/source/T3D/shapeImage.cpp

@@ -293,8 +293,7 @@ ShapeBaseImageData::ShapeBaseImageData()
       isAnimated[i] = false;
       hasFlash[i] = false;
       shapeIsValid[i] = false;
-
-      INIT_ASSET_ARRAY(Shape, i);
+      mShapeAsset[i].registerRefreshNotify(this);
    }
 
    shakeCamera = false;
@@ -454,10 +453,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
 
       if (!mShapeAsset[i].isNull())
       {
-         // Resolve shapename
-         mShape[i] = mShapeAsset[i]->getShapeResource();
-
-         if (!bool(mShape[i])) {
+         if (!bool(getShape(i))) {
             errorStr = String::ToString("Unable to load shape asset: %s", mShapeAsset[i]->getAssetId());
             return false;
          }
@@ -465,7 +461,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
          {
             Con::printf("Validation required for shape asset: %s", mShapeAsset[i]->getAssetId());
 
-            Torque::FS::FileNodeRef    fileRef = Torque::FS::GetFileNode(mShape[i].getPath());
+            Torque::FS::FileNodeRef    fileRef = Torque::FS::GetFileNode(getShape(i).getPath());
 
             if (!fileRef)
             {
@@ -485,23 +481,23 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
          }
 
          // Resolve nodes & build mount transform
-         eyeMountNode[i] = mShape[i]->findNode("eyeMount");
-         eyeNode[i] = mShape[i]->findNode("eye");
+         eyeMountNode[i]   = getShape(i)->findNode("eyeMount");
+         eyeNode[i]        = getShape(i)->findNode("eye");
          if (eyeNode[i] == -1)
             eyeNode[i] = eyeMountNode[i];
-         ejectNode[i] = mShape[i]->findNode("ejectPoint");
-         muzzleNode[i] = mShape[i]->findNode("muzzlePoint");
-         retractNode[i] = mShape[i]->findNode("retractionPoint");
+         ejectNode[i]      = getShape(i)->findNode("ejectPoint");
+         muzzleNode[i]     = getShape(i)->findNode("muzzlePoint");
+         retractNode[i]    = getShape(i)->findNode("retractionPoint");
          mountTransform[i] = mountOffset;
-         S32 node = mShape[i]->findNode("mountPoint");
+         S32 node          = getShape(i)->findNode("mountPoint");
          if (node != -1) {
             MatrixF total(1);
             do {
                MatrixF nmat;
                QuatF q;
-               TSTransform::setMatrix(mShape[i]->defaultRotations[node].getQuatF(&q), mShape[i]->defaultTranslations[node],&nmat);
+               TSTransform::setMatrix(getShape(i)->defaultRotations[node].getQuatF(&q), getShape(i)->defaultTranslations[node],&nmat);
                total.mul(nmat);
-               node = mShape[i]->nodes[node].parentIndex;
+               node = getShape(i)->nodes[node].parentIndex;
             }
             while(node != -1);
             total.inverse();
@@ -514,7 +510,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
          for (U32 j = 0; j < MaxStates; j++) {
             StateData& s = state[j];
             if (stateSequence[j] && stateSequence[j][0])
-               s.sequence[i] = mShape[i]->findSequence(stateSequence[j]);
+               s.sequence[i] = getShape(i)->findSequence(stateSequence[j]);
             if (s.sequence[i] != -1)
             {
                // This state has an animation sequence
@@ -525,7 +521,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
                char bufferVis[128];
                dStrncpy(bufferVis, stateSequence[j], 100);
                dStrcat(bufferVis, "_vis", 128);
-               s.sequenceVis[i] = mShape[i]->findSequence(bufferVis);
+               s.sequenceVis[i] = getShape(i)->findSequence(bufferVis);
             }
             if (s.sequenceVis[i] != -1)
             {
@@ -537,13 +533,13 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
             s.ignoreLoadedForReady = stateIgnoreLoadedForReady[j];
 
             if (stateEmitterNode[j] && stateEmitterNode[j][0])
-               s.emitterNode[i] = mShape[i]->findNode(stateEmitterNode[j]);
+               s.emitterNode[i] = getShape(i)->findNode(stateEmitterNode[j]);
             if (s.emitterNode[i] == -1)
                s.emitterNode[i] = muzzleNode[i];
          }
 
-         ambientSequence[i] = mShape[i]->findSequence("ambient");
-         spinSequence[i] = mShape[i]->findSequence("spin");
+         ambientSequence[i]   = getShape(i)->findSequence("ambient");
+         spinSequence[i]      = getShape(i)->findSequence("spin");
 
          shapeIsValid[i] = true;
       }
@@ -567,7 +563,7 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
    {
       if( shapeIsValid[i] )
       {
-         TSShapeInstance* pDummy = new TSShapeInstance(mShape[i], !server);
+         TSShapeInstance* pDummy = new TSShapeInstance(getShape(i), !server);
          delete pDummy;
       }
    }
@@ -628,8 +624,8 @@ void ShapeBaseImageData::initPersistFields()
 {
    docsURL;
    addGroup("Shapes");
-      INITPERSISTFIELD_SHAPEASSET_ARRAY(Shape, MaxShapes, ShapeBaseImageData, "The shape asset to use for this image in the third person")
-   //addProtectedField("shapeFileFP", TypeShapeFilename, Offset(mShapeName[1], ShapeBaseImageData), _setShapeData, defaultProtectedGetFn, "deprecated alias for ShapeFPFile/Asset", AbstractClassRep::FIELD_HideInInspectors);
+   INITPERSISTFIELD_SHAPEASSET_ARRAY_REFACTOR(Shape, MaxShapes, ShapeBaseImageData, "The shape assets for this shape image")
+
       addField("casing", TYPEID< DebrisData >(), Offset(casing, ShapeBaseImageData),
             "@brief DebrisData datablock to use for ejected casings.\n\n"
             "@see stateEjectShell");
@@ -1002,10 +998,7 @@ void ShapeBaseImageData::packData(BitStream* stream)
       }
    }
 
-   for (U32 j = 0; j < MaxShapes; ++j)
-   {
-      PACKDATA_ASSET_ARRAY(Shape, j);        // shape 0 for normal use, shape 1 for first person use (optional)
-   }
+   PACKDATA_ASSET_ARRAY_REFACTOR(Shape, MaxShapes);        // shape 0 for normal use, shape 1 for first person use (optional)
 
    stream->writeString(imageAnimPrefix);
    stream->writeString(imageAnimPrefixFP);
@@ -1186,10 +1179,7 @@ void ShapeBaseImageData::unpackData(BitStream* stream)
       }
    }
 
-   for (U32 j = 0; j < MaxShapes; ++j)
-   {
-      UNPACKDATA_ASSET_ARRAY(Shape, j);        // shape 0 for normal use, shape 1 for first person use (optional)
-   }
+   UNPACKDATA_ASSET_ARRAY_REFACTOR(Shape, MaxShapes);        // shape 0 for normal use, shape 1 for first person use (optional)
 
    imageAnimPrefix = stream->readSTString();
    imageAnimPrefixFP = stream->readSTString();
@@ -2148,7 +2138,7 @@ S32 ShapeBase::getNodeIndex(U32 imageSlot,StringTableEntry nodeName)
 {
    MountedImage& image = mMountedImageList[imageSlot];
    if (image.dataBlock)
-      return image.dataBlock->mShape[getImageShapeIndex(image)]->findNode(nodeName);
+      return image.dataBlock->getShape(getImageShapeIndex(image))->findNode(nodeName);
    else
       return -1;
 }
@@ -2338,7 +2328,7 @@ void ShapeBase::setImage(  U32 imageSlot,
    for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
    {
       if (image.dataBlock->shapeIsValid[i])
-         image.shapeInstance[i] = new TSShapeInstance(image.dataBlock->mShape[i], isClientObject());
+         image.shapeInstance[i] = new TSShapeInstance(image.dataBlock->getShape(i), isClientObject());
    }
 
    if (isClientObject())

+ 53 - 60
Engine/source/T3D/tsStatic.cpp

@@ -151,13 +151,14 @@ TSStatic::TSStatic()
    mAnimOffset = 0.0f;
    mAnimSpeed = 1.0f;
 
-   INIT_ASSET(Shape);
+   mShapeAsset.registerRefreshNotify(this);
 }
 
 TSStatic::~TSStatic()
 {
    delete mConvexList;
    mConvexList = NULL;
+   mShapeAsset.unregisterRefreshNotify();
 }
 
 ImplementEnumType(TSMeshType,
@@ -180,11 +181,7 @@ void TSStatic::initPersistFields()
    docsURL;
    addGroup("Shape");
 
-   INITPERSISTFIELD_SHAPEASSET(Shape, TSStatic, "Model to use for this TSStatic");
-
-   addProtectedField("shapeName", TypeShapeFilename, Offset(mShapeName, TSStatic),
-      &TSStatic::_setShapeData, &defaultProtectedGetFn,
-      "%Path and filename of the model file (.DTS, .DAE) to use for this TSStatic. Legacy field. Any loose files assigned here will attempt to be auto-imported in as an asset.", AbstractClassRep::FIELD_HideInInspectors);
+   INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, TSStatic, "Model to use for this TSStatic");
 
    endGroup("Shape");
 
@@ -393,59 +390,55 @@ bool TSStatic::_createShape()
    mAmbientThread = NULL;
    //mShape = NULL;
 
-   U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset);
-   if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback)
+   if (mShapeAsset.notNull())
    {
-      //Special-case handling, usually because we set noShape
-      mShape = mShapeAsset->getShapeResource();
-   }
-
-   if (!mShape)
-   {
-      Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAsset.getAssetId());
-      return false;
-   }
+      if (!getShape())
+      {
+         Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAsset.getAssetId());
+         return false;
+      }
 
-   if (isClientObject() &&
-      !mShape->preloadMaterialList(mShape.getPath()) &&
-      NetConnection::filesWereDownloaded())
-      return false;
+      if (isClientObject() &&
+         !getShape()->preloadMaterialList(getShape().getPath()) &&
+         NetConnection::filesWereDownloaded())
+         return false;
 
-   mObjBox = mShape->mBounds;
-   resetWorldBox();
+      mObjBox = getShape()->mBounds;
+      resetWorldBox();
 
-   mShapeInstance = new TSShapeInstance(mShape, isClientObject());
-   mShapeInstance->resetMaterialList();
-   mShapeInstance->cloneMaterialList();
+      mShapeInstance = new TSShapeInstance(getShape(), isClientObject());
+      mShapeInstance->resetMaterialList();
+      mShapeInstance->cloneMaterialList();
 
-   if (isGhost())
-   {
-      // Reapply the current skin
-      mAppliedSkinName = "";
-      reSkin();
+      if (isGhost())
+      {
+         // Reapply the current skin
+         mAppliedSkinName = "";
+         reSkin();
 
-      updateMaterials();
-   }
+         updateMaterials();
+      }
 
-   prepCollision();
+      prepCollision();
 
-   // Find the "ambient" animation if it exists
-   S32 ambientSeq = mShape->findSequence("ambient");
+      // Find the "ambient" animation if it exists
+      S32 ambientSeq = getShape()->findSequence("ambient");
 
-   if (ambientSeq > -1 && !mAmbientThread)
-      mAmbientThread = mShapeInstance->addThread();
+      if (ambientSeq > -1 && !mAmbientThread)
+         mAmbientThread = mShapeInstance->addThread();
 
-   if ( mAmbientThread )
-      mShapeInstance->setSequence(mAmbientThread, ambientSeq, mAnimOffset);
+      if ( mAmbientThread )
+         mShapeInstance->setSequence(mAmbientThread, ambientSeq, mAnimOffset);
 
-   // Resolve CubeReflectorDesc.
-   if (cubeDescName.isNotEmpty())
-   {
-      Sim::findObject(cubeDescName, reflectorDesc);
-   }
-   else if (cubeDescId > 0)
-   {
-      Sim::findObject(cubeDescId, reflectorDesc);
+      // Resolve CubeReflectorDesc.
+      if (cubeDescName.isNotEmpty())
+      {
+         Sim::findObject(cubeDescName, reflectorDesc);
+      }
+      else if (cubeDescId > 0)
+      {
+         Sim::findObject(cubeDescId, reflectorDesc);
+      }
    }
 
    //Set up the material slot vars for easy manipulation
@@ -533,20 +526,20 @@ void TSStatic::prepCollision()
 
    if (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh)
    {
-      mShape->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails, mCollisionLOD);
+      getShape()->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails, mCollisionLOD);
       if (mDecalType == mCollisionType)
       {
          mDecalDetailsPtr = &mCollisionDetails;
       }
       else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh)
       {
-         mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD);
+         getShape()->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD);
          mDecalDetailsPtr = &mDecalDetails;
       }
    }
    else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh)
    {
-      mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD);
+      getShape()->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0, mCollisionLOD);
       mDecalDetailsPtr = &mDecalDetails;
    }
 
@@ -564,12 +557,12 @@ void TSStatic::_updatePhysics()
    if (mCollisionType == Bounds)
    {
       MatrixF offset(true);
-      offset.setPosition(mShape->center);
+      offset.setPosition(getShape()->center);
       colShape = PHYSICSMGR->createCollision();
       colShape->addBox(getObjBox().getExtents() * 0.5f * mObjScale, offset);
    }
    else
-      colShape = mShape->buildColShape(mCollisionType == VisibleMesh, getScale());
+      colShape = getShape()->buildColShape(mCollisionType == VisibleMesh, getScale());
 
    if (colShape)
    {
@@ -958,7 +951,7 @@ U32 TSStatic::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
 
    if (stream->writeFlag(mask & AdvancedStaticOptionsMask))
    {
-      PACK_ASSET(con, Shape);
+      PACK_ASSET_REFACTOR(con, Shape);
 
       stream->write((U32)mDecalType);
 
@@ -1074,7 +1067,7 @@ void TSStatic::unpackUpdate(NetConnection* con, BitStream* stream)
 
    if (stream->readFlag()) // AdvancedStaticOptionsMask
    {
-      UNPACK_ASSET(con, Shape);
+      UNPACK_ASSET_REFACTOR(con, Shape);
 
       stream->read((U32*)&mDecalType);
 
@@ -1596,7 +1589,7 @@ void TSStatic::updateMaterials()
    if (mShapeAsset->isAssetValid())
       path = mShapeAsset->getShapeFileName();
    else
-      path = mShapeName;
+      path = mShapeFile;
 
    pMatList->setTextureLookupPath(path);
 
@@ -1778,7 +1771,7 @@ DefineEngineMethod(TSStatic, changeMaterial, void, (const char* mapTo, Material*
       return;
    }
 
-   TSMaterialList* shapeMaterialList = object->getShapeResource()->materialList;
+   TSMaterialList* shapeMaterialList = object->getShape()->materialList;
 
    // Check the mapTo name exists for this shape
    S32 matIndex = shapeMaterialList->getMaterialNameList().find_next(String(mapTo));
@@ -1818,7 +1811,7 @@ DefineEngineMethod(TSStatic, getModelFile, const char*, (), ,
    "@endtsexample\n"
 )
 {
-   return object->getShape();
+   return object->getShapeFile();
 }
 
 void TSStatic::set_special_typing()
@@ -1863,14 +1856,14 @@ void TSStatic::setSelectionFlags(U8 flags)
 bool TSStatic::hasNode(const char* nodeName)
 {
 
-   S32 nodeIDx = getShapeResource()->findNode(nodeName);
+   S32 nodeIDx = getShape()->findNode(nodeName);
    return nodeIDx >= 0;
 }
 
 void TSStatic::getNodeTransform(const char *nodeName, const MatrixF &xfm, MatrixF *outMat)
 {
 
-    S32 nodeIDx = getShapeResource()->findNode(nodeName);
+    S32 nodeIDx = getShape()->findNode(nodeName);
 
     MatrixF nodeTransform(xfm);
     const Point3F& scale = getScale();

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

@@ -101,7 +101,7 @@ public:
 
 
 /// A simple mesh shape with optional ambient animation.
-class TSStatic : public SceneObject
+class TSStatic : public SceneObject, protected AssetPtrCallback
 {
    typedef SceneObject Parent;
 
@@ -186,12 +186,17 @@ protected:
    ReflectorDesc* reflectorDesc;
    CubeReflector mCubeReflector;
 
+   void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override
+   {
+      _createShape();
+      _updateShouldTick();
+   }
+
 protected:
 
    Convex* mConvexList;
 
-   DECLARE_SHAPEASSET(TSStatic, Shape, onShapeChanged);
-   DECLARE_ASSET_NET_SETGET(TSStatic, Shape, AdvancedStaticOptionsMask);
+   DECLARE_SHAPEASSET_NET_REFACTOR(TSStatic, Shape, AdvancedStaticOptionsMask)
 
    U32               mShapeHash;
    Vector<S32> mCollisionDetails;
@@ -239,7 +244,7 @@ public:
    DECLARE_CATEGORY("Object \t Simple");
    static void initPersistFields();
    /// returns the shape asset used for this object
-   StringTableEntry getTypeHint() const override { return (getShapeAsset()) ? getShapeAsset()->getAssetName(): StringTable->EmptyString(); }
+   StringTableEntry getTypeHint() const override { return (mShapeAsset.notNull()) ? mShapeAsset->getAssetName(): StringTable->EmptyString(); }
    static void consoleInit();
    static bool _setFieldSkin(void* object, const char* index, const char* data);
    static const char* _getFieldSkin(void* object, const char* data);

+ 3 - 3
Engine/source/T3D/turret/aiTurretShape.cpp

@@ -246,8 +246,8 @@ bool AITurretShapeData::preload(bool server, String &errorStr)
       return false;
 
    // We have mShape at this point.  Resolve nodes.
-   scanNode = mShape->findNode("scanPoint");
-   aimNode = mShape->findNode("aimPoint");
+   scanNode = getShape()->findNode("scanPoint");
+   aimNode = getShape()->findNode("aimPoint");
 
    if (scanNode == -1) scanNode = pitchNode;
    if (scanNode == -1) scanNode = headingNode;
@@ -259,7 +259,7 @@ bool AITurretShapeData::preload(bool server, String &errorStr)
    for (U32 j = 0; j < MaxStates; j++) {
       StateData& s = state[j];
       if (stateSequence[j] && stateSequence[j][0])
-         s.sequence = mShape->findSequence(stateSequence[j]);
+         s.sequence = getShape()->findSequence(stateSequence[j]);
       if (s.sequence != -1)
       {
          // This state has an animation sequence

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

@@ -217,35 +217,35 @@ bool TurretShapeData::preload(bool server, String &errorStr)
       return false;
 
    // We have mShape at this point.  Resolve nodes.
-   headingNode = mShape->findNode("heading");
-   pitchNode = mShape->findNode("pitch");
+   headingNode = getShape()->findNode("heading");
+   pitchNode = getShape()->findNode("pitch");
 
    // Find any mirror pitch nodes
    for (U32 i = 0; i < NumMirrorDirectionNodes; ++i)
    {
       char name[32];
       dSprintf(name, 31, "pitch%d", i+1);
-      pitchNodes[i] = mShape->findNode(name);
+      pitchNodes[i] = getShape()->findNode(name);
 
       dSprintf(name, 31, "heading%d", i+1);
-      headingNodes[i] = mShape->findNode(name);
+      headingNodes[i] = getShape()->findNode(name);
    }
 
    // Resolve weapon mount point node indexes
    for (U32 i = 0; i < ShapeBase::MaxMountedImages; i++) {
       char fullName[256];
       dSprintf(fullName,sizeof(fullName),"weaponMount%d",i);
-      weaponMountNode[i] = mShape->findNode(fullName);
+      weaponMountNode[i] = getShape()->findNode(fullName);
    }
 
    // Recoil animations
-   recoilSequence[0] = mShape->findSequence("light_recoil");
-   recoilSequence[1] = mShape->findSequence("medium_recoil");
-   recoilSequence[2] = mShape->findSequence("heavy_recoil");
+   recoilSequence[0] = getShape()->findSequence("light_recoil");
+   recoilSequence[1] = getShape()->findSequence("medium_recoil");
+   recoilSequence[2] = getShape()->findSequence("heavy_recoil");
 
    // Optional sequences used when the turret rotates
-   pitchSequence = mShape->findSequence("pitch");
-   headingSequence = mShape->findSequence("heading");
+   pitchSequence = getShape()->findSequence("pitch");
+   headingSequence = getShape()->findSequence("heading");
 
    return true;
 }

+ 2 - 2
Engine/source/T3D/vehicles/flyingVehicle.cpp

@@ -135,7 +135,7 @@ bool FlyingVehicleData::preload(bool server, String &errorStr)
    if (!Parent::preload(server, errorStr))
       return false;
 
-   TSShapeInstance* si = new TSShapeInstance(mShape, false);
+   TSShapeInstance* si = new TSShapeInstance(getShape(), false);
 
    // Resolve objects transmitted from server
    if (!server) {
@@ -164,7 +164,7 @@ bool FlyingVehicleData::preload(bool server, String &errorStr)
 
    // Resolve jet nodes
    for (S32 j = 0; j < MaxJetNodes; j++)
-      jetNode[j] = mShape->findNode(sJetNode[j]);
+      jetNode[j] = getShape()->findNode(sJetNode[j]);
 
    //
    maxSpeed = maneuveringForce / minDrag;

+ 1 - 1
Engine/source/T3D/vehicles/hoverVehicle.cpp

@@ -332,7 +332,7 @@ bool HoverVehicleData::preload(bool server, String &errorStr)
    }
    // Resolve jet nodes
    for (S32 j = 0; j < MaxJetNodes; j++)
-      jetNode[j] = mShape->findNode(sJetNode[j]);
+      jetNode[j] = getShape()->findNode(sJetNode[j]);
 
    return true;
 }

+ 1 - 1
Engine/source/T3D/vehicles/vehicle.cpp

@@ -163,7 +163,7 @@ bool VehicleData::preload(bool server, String &errorStr)
    if (!collisionDetails.size() || collisionDetails[0] == -1)
    {
       Con::errorf("VehicleData::preload failed: Vehicle models must define a collision-1 detail");
-      errorStr = String::ToString("VehicleData: Couldn't load shape asset \"%s\"", mShapeAsset.getAssetId());
+      errorStr = String::ToString("VehicleData: Couldn't load shape asset \"%s\"", getShapeAsset().getAssetId());
       return false;
    }
 

+ 16 - 17
Engine/source/T3D/vehicles/wheeledVehicle.cpp

@@ -75,8 +75,6 @@ ConsoleDocClass( WheeledVehicleTire,
 
 WheeledVehicleTire::WheeledVehicleTire()
 {
-   INIT_ASSET(Shape);
-
    staticFriction = 1;
    kineticFriction = 0.5f;
    restitution = 1;
@@ -88,15 +86,16 @@ WheeledVehicleTire::WheeledVehicleTire()
    longitudinalDamping = 1;
    longitudinalRelaxation = 1;
    mass = 1.f;
+   mShapeAsset.registerRefreshNotify(this);
 }
 
 bool WheeledVehicleTire::preload(bool server, String &errorStr)
 {
    // Load up the tire shape.  ShapeBase has an option to force a
    // CRC check, this is left out here, but could be easily added.
-   if (!mShape)
+   if (!getShape())
    {
-      errorStr = String::ToString("WheeledVehicleTire: Couldn't load shape \"%s\"", mShapeAssetId);
+      errorStr = String::ToString("WheeledVehicleTire: Couldn't load shape \"%s\"", _getShapeAssetId());
       return false;
    }
    else
@@ -104,7 +103,7 @@ bool WheeledVehicleTire::preload(bool server, String &errorStr)
       // Determinw wheel radius from the shape's bounding box.
       // The tire should be built with it's hub axis along the
       // object's Y axis.
-      radius = mShape->mBounds.len_z() / 2;
+      radius = getShape()->mBounds.len_z() / 2;
    }
 
    return true;
@@ -113,7 +112,7 @@ bool WheeledVehicleTire::preload(bool server, String &errorStr)
 void WheeledVehicleTire::initPersistFields()
 {
    docsURL;
-   INITPERSISTFIELD_SHAPEASSET(Shape, WheeledVehicleTire, "The shape to use for the wheel.");
+   INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, WheeledVehicleTire, "The shape to use for the wheel.");
 
    addFieldV( "mass", TypeRangedF32, Offset(mass, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "The mass of the wheel.\nCurrently unused." );
@@ -178,7 +177,7 @@ void WheeledVehicleTire::packData(BitStream* stream)
 {
    Parent::packData(stream);
 
-   PACKDATA_ASSET(Shape);
+   PACKDATA_ASSET_REFACTOR(Shape);
 
    stream->write(mass);
    stream->write(staticFriction);
@@ -197,7 +196,7 @@ void WheeledVehicleTire::unpackData(BitStream* stream)
 {
    Parent::unpackData(stream);
 
-   UNPACKDATA_ASSET(Shape);
+   UNPACKDATA_ASSET_REFACTOR(Shape);
 
    stream->read(&mass);
    stream->read(&staticFriction);
@@ -343,7 +342,7 @@ bool WheeledVehicleData::preload(bool server, String &errorStr)
 
    // A temporary shape instance is created so that we can
    // animate the shape and extract wheel information.
-   TSShapeInstance* si = new TSShapeInstance(mShape, false);
+   TSShapeInstance* si = new TSShapeInstance(getShape(), false);
 
    // Resolve objects transmitted from server
    if (!server) {
@@ -367,14 +366,14 @@ bool WheeledVehicleData::preload(bool server, String &errorStr)
 
       // The wheel must have a hub node to operate at all.
       dSprintf(buff,sizeof(buff),"hub%d",i);
-      wp->springNode = mShape->findNode(buff);
+      wp->springNode = getShape()->findNode(buff);
       if (wp->springNode != -1) {
 
          // Check for spring animation.. If there is none we just grab
          // the current position of the hub. Otherwise we'll animate
          // and get the position at time 0.
          dSprintf(buff,sizeof(buff),"spring%d",i);
-         wp->springSequence = mShape->findSequence(buff);
+         wp->springSequence = getShape()->findSequence(buff);
          if (wp->springSequence == -1)
             si->mNodeTransforms[wp->springNode].getColumn(3, &wp->pos);
          else {
@@ -403,17 +402,17 @@ bool WheeledVehicleData::preload(bool server, String &errorStr)
    // Check for steering. Should think about normalizing the
    // steering animation the way the suspension is, but I don't
    // think it's as critical.
-   steeringSequence = mShape->findSequence("steering");
+   steeringSequence = getShape()->findSequence("steering");
 
    // Brakes
-   brakeLightSequence = mShape->findSequence("brakelight");
+   brakeLightSequence = getShape()->findSequence("brakelight");
 
    // Extract collision planes from shape collision detail level
    if (collisionDetails[0] != -1) {
       MatrixF imat(1);
       SphereF sphere;
-      sphere.center = mShape->center;
-      sphere.radius = mShape->mRadius;
+      sphere.center = getShape()->center;
+      sphere.radius = getShape()->mRadius;
       PlaneExtractorPolyList polyList;
       polyList.mPlaneList = &rigidBody.mPlaneList;
       polyList.setTransform(&imat, Point3F(1,1,1));
@@ -1579,8 +1578,8 @@ void WheeledVehicle::unpackUpdate(NetConnection *con, BitStream *stream)
 
             // Create an instance of the tire for rendering
             delete wheel->shapeInstance;
-            wheel->shapeInstance = (wheel->tire->mShape == NULL) ? 0:
-               new TSShapeInstance(wheel->tire->mShape);
+            wheel->shapeInstance = (wheel->tire->getShape() == NULL) ? 0:
+               new TSShapeInstance(wheel->tire->getShape());
          }
       }
    }

+ 4 - 4
Engine/source/T3D/vehicles/wheeledVehicle.h

@@ -39,12 +39,11 @@ class ParticleEmitterData;
 
 //----------------------------------------------------------------------------
 
-struct WheeledVehicleTire: public SimDataBlock 
+struct WheeledVehicleTire: public SimDataBlock, protected AssetPtrCallback
 {
    typedef SimDataBlock Parent;
 
-   DECLARE_SHAPEASSET(WheeledVehicleTire, Shape, onShapeChanged);
-   DECLARE_ASSET_SETGET(WheeledVehicleTire, Shape);
+   DECLARE_SHAPEASSET_REFACTOR(WheeledVehicleTire, Shape)
 
    // Physical properties
    F32 mass;                  // Mass of the whole wheel
@@ -74,7 +73,8 @@ struct WheeledVehicleTire: public SimDataBlock
    void packData(BitStream* stream) override;
    void unpackData(BitStream* stream) override;
 
-   void onShapeChanged()
+protected:
+   void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override
    {
       reloadOnLocalClient();
    }

+ 10 - 7
Engine/source/afx/afxMagicMissile.cpp

@@ -141,7 +141,6 @@ U32 Projectile::smProjectileWarpTicks = 5;
 //
 afxMagicMissileData::afxMagicMissileData()
 {
-   INIT_ASSET(ProjectileShape);
    INIT_ASSET(ProjectileSound);
 
    /* From stock Projectile code...
@@ -241,11 +240,13 @@ afxMagicMissileData::afxMagicMissileData()
   reverse_targeting = false;
 
   caster_safety_time = U32_MAX;
+
+  mProjectileShapeAsset.registerRefreshNotify(this);
 }
 
 afxMagicMissileData::afxMagicMissileData(const afxMagicMissileData& other, bool temp_clone) : GameBaseData(other, temp_clone)
 {
-   CLONE_ASSET(ProjectileShape);
+   mProjectileShapeAsset = other.mProjectileShapeAsset;
   projectileShape = other.projectileShape; // -- TSShape loads using projectileShapeName
   CLONE_ASSET(ProjectileSound);
   splash = other.splash;
@@ -305,6 +306,8 @@ afxMagicMissileData::~afxMagicMissileData()
 {
   if (wiggle_axis)
     delete [] wiggle_axis;
+
+  mProjectileShapeAsset.unregisterRefreshNotify();
 }
 
 afxMagicMissileData* afxMagicMissileData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index)
@@ -334,7 +337,7 @@ void afxMagicMissileData::initPersistFields()
    static IRangeValidatorScaled ticksFromMS(TickMs, 0, MaxLifetimeTicks);
 
    addGroup("Shapes");
-      INITPERSISTFIELD_SHAPEASSET(ProjectileShape, afxMagicMissileData, "Shape for the projectile");
+      INITPERSISTFIELD_SHAPEASSET_REFACTOR(ProjectileShape, afxMagicMissileData, "Shape for the projectile");
       addField("scale", TypePoint3F, Offset(scale, afxMagicMissileData));
       addField("missileShapeScale",   TypePoint3F,  myOffset(scale));
    endGroup("Shapes");
@@ -531,10 +534,10 @@ bool afxMagicMissileData::preload(bool server, String &errorStr)
    U32 assetStatus = ShapeAsset::getAssetErrCode(mProjectileShapeAsset);
    if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback)
    {
-      projectileShape = mProjectileShapeAsset->getShapeResource();
+      projectileShape = getProjectileShape();
       if (bool(projectileShape) == false)
       {
-         errorStr = String::ToString("afxMagicMissileData::preload: Couldn't load shape \"%s\"", mProjectileShapeAssetId);
+         errorStr = String::ToString("afxMagicMissileData::preload: Couldn't load shape \"%s\"", _getProjectileShapeAssetId());
          return false;
       }
       /* From stock Projectile code...
@@ -586,7 +589,7 @@ void afxMagicMissileData::packData(BitStream* stream)
 {
    Parent::packData(stream);
 
-   PACKDATA_ASSET(ProjectileShape);
+   PACKDATA_ASSET_REFACTOR(ProjectileShape);
 
    /* From stock Projectile code...
    stream->writeFlag(faceViewer);
@@ -697,7 +700,7 @@ void afxMagicMissileData::unpackData(BitStream* stream)
 {
    Parent::unpackData(stream);
 
-   UNPACKDATA_ASSET(ProjectileShape);
+   UNPACKDATA_ASSET_REFACTOR(ProjectileShape);
    /* From stock Projectile code...
    faceViewer = stream->readFlag();
    */

+ 8 - 8
Engine/source/afx/afxMagicMissile.h

@@ -56,7 +56,7 @@ class SFXSource;
 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 // afxMagicMissileData
 
-class afxMagicMissileData : public GameBaseData
+class afxMagicMissileData : public GameBaseData, protected AssetPtrCallback
 {
   typedef GameBaseData Parent;
   
@@ -66,16 +66,10 @@ protected:
 public:
   enum { MaxLifetimeTicks = 4095 };
 
-  void onShapeChanged()
-  {
-     reloadOnLocalClient();
-  }
-  
 public:
    // variables set in datablock definition:
    // Shape related
-   DECLARE_SHAPEASSET(afxMagicMissileData, ProjectileShape, onShapeChanged);
-   DECLARE_ASSET_SETGET(afxMagicMissileData, ProjectileShape);
+   DECLARE_SHAPEASSET_REFACTOR(afxMagicMissileData, ProjectileShape)
   //StringTableEntry      projectileShapeName;
 
   //bool                  hasLight;
@@ -228,6 +222,12 @@ public:
   afxMagicMissileData*  cloneAndPerformSubstitutions(const SimObject*, S32 index=0);
   bool          allowSubstitutions() const override { return true; }
   void                  gather_cons_defs(Vector<afxConstraintDef>& defs);
+
+protected:
+   void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override
+   {
+      reloadOnLocalClient();
+   }
 };
 
 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

+ 26 - 34
Engine/source/afx/ce/afxModel.cpp

@@ -54,7 +54,6 @@ ConsoleDocClass( afxModelData,
 
 afxModelData::afxModelData()
 {
-   INIT_ASSET(Shape);
   sequence = ST_NULLSTRING;
   seq_rate = 1.0f;
   seq_offset = 0.0f;
@@ -79,11 +78,13 @@ afxModelData::afxModelData()
   shadowMaxVisibleDistance = 80.0f;
   shadowProjectionDistance = 10.0f;
   shadowSphereAdjust = 1.0;
+
+  mShapeAsset.registerRefreshNotify(this);
 }
 
 afxModelData::afxModelData(const afxModelData& other, bool temp_clone) : GameBaseData(other, temp_clone)
 {
-   CLONE_ASSET(Shape);
+   mShapeAsset = other.mShapeAsset;
   sequence = other.sequence;
   seq_rate = other.seq_rate;
   seq_offset = other.seq_offset;
@@ -113,6 +114,8 @@ afxModelData::~afxModelData()
 {
    if (remap_buffer)
       dFree(remap_buffer);
+
+   mShapeAsset.unregisterRefreshNotify();
 }
 
 bool afxModelData::preload(bool server, String &errorStr)
@@ -126,9 +129,9 @@ bool afxModelData::preload(bool server, String &errorStr)
   
   if (mShapeAsset.notNull())
   {
-    if (!mShape)
+    if (!getShape())
     {
-      errorStr = String::ToString("afxModelData::load: Failed to load shape \"%s\"", mShapeAssetId);
+      errorStr = String::ToString("afxModelData::load: Failed to load shape \"%s\"", _getShapeAssetId());
       return false;
     }
 
@@ -160,7 +163,7 @@ bool afxModelData::preload(bool server, String &errorStr)
     if (txr_tag_remappings.size() == 0)
     {
       // this little hack forces the textures to preload
-      TSShapeInstance* pDummy = new TSShapeInstance(mShape);
+      TSShapeInstance* pDummy = new TSShapeInstance(getShape());
       delete pDummy;
     }
   }
@@ -174,7 +177,7 @@ void afxModelData::initPersistFields()
 {
    docsURL;
    addGroup("Shapes");
-      INITPERSISTFIELD_SHAPEASSET(Shape, afxModelData, "The name of a .dts format file to use for the model.");
+      INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, afxModelData, "The name of a .dts format file to use for the model.");
    endGroup("Shapes");
 
    addGroup("Animation");
@@ -258,7 +261,7 @@ void afxModelData::packData(BitStream* stream)
 {
   Parent::packData(stream);
 
-  PACKDATA_ASSET(Shape);
+  PACKDATA_ASSET_REFACTOR(Shape);
   stream->writeString(sequence);
   stream->write(seq_rate);  
   stream->write(seq_offset);
@@ -289,7 +292,7 @@ void afxModelData::unpackData(BitStream* stream)
 {
   Parent::unpackData(stream);
 
-  UNPACKDATA_ASSET(Shape);
+  UNPACKDATA_ASSET_REFACTOR(Shape);
   sequence = stream->readSTString();
   stream->read(&seq_rate);
   stream->read(&seq_offset);
@@ -318,21 +321,10 @@ void afxModelData::unpackData(BitStream* stream)
 
 void afxModelData::onPerformSubstitutions()
 {
-   if (mShapeAssetId != StringTable->EmptyString())
+   if (!getShape())
    {
-      mShapeAsset = mShapeAssetId;
-      if (mShapeAsset.notNull())
-      {
-         mShape = mShapeAsset->getShapeResource();
-      }
-
-      if (!mShape)
-      {
-         Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape \"%s\"", mShapeAssetId);
-         return;
-      }
-
-      // REMAP-TEXTURE-TAGS ISSUES?
+      Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape \"%s\"", _getShapeAssetId());
+      return;
    }
 }
 
@@ -406,18 +398,18 @@ bool afxModel::onAdd()
     return false;
 
   // setup our bounding box
-  if (mDataBlock->mShape)
-    mObjBox = mDataBlock->mShape->mBounds;
+  if (mDataBlock->getShape())
+    mObjBox = mDataBlock->getShape()->mBounds;
   else
     mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
 
   // setup the shape instance and sequence
-  if (mDataBlock->mShape)
+  if (mDataBlock->getShape())
   {
      if (/*isClientObject() && */mDataBlock->txr_tag_remappings.size() > 0)
      {
         // temporarily substitute material tags with alternates
-        TSMaterialList* mat_list = mDataBlock->mShape->materialList;
+        TSMaterialList* mat_list = mDataBlock->getShape()->materialList;
         if (mat_list)
         {
            for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++)
@@ -438,7 +430,7 @@ bool afxModel::onAdd()
         }
      }
 
-    shape_inst = new TSShapeInstance(mDataBlock->mShape);
+    shape_inst = new TSShapeInstance(mDataBlock->getShape());
 
     if (true) // isClientObject())
     {
@@ -447,7 +439,7 @@ bool afxModel::onAdd()
        // restore the material tags to original form
        if (mDataBlock->txr_tag_remappings.size() > 0)
        {
-          TSMaterialList* mat_list = mDataBlock->mShape->materialList;
+          TSMaterialList* mat_list = mDataBlock->getShape()->materialList;
           if (mat_list)
           {
              for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++)
@@ -513,14 +505,14 @@ bool afxModel::onAdd()
 
   resetWorldBox();
 
-  if (mDataBlock->mShape)
+  if (mDataBlock->getShape())
   {
     // Scan out the collision hulls...
     static const String sCollisionStr( "collision-" );
 
-    for (U32 i = 0; i < mDataBlock->mShape->details.size(); i++)
+    for (U32 i = 0; i < mDataBlock->getShape()->details.size(); i++)
     {
-      const String &name = mDataBlock->mShape->names[mDataBlock->mShape->details[i].nameIndex];
+      const String &name = mDataBlock->getShape()->names[mDataBlock->getShape()->details[i].nameIndex];
 
       if (name.compare( sCollisionStr, sCollisionStr.length(), String::NoCase ) == 0)
       {
@@ -534,7 +526,7 @@ bool afxModel::onAdd()
 
         char buff[128];
         dSprintf(buff, sizeof(buff), "LOS-%d", i + 1 + 8/*MaxCollisionShapes*/);
-        U32 los = mDataBlock->mShape->findDetail(buff);
+        U32 los = mDataBlock->getShape()->findDetail(buff);
         if (los == -1)
           mLOSDetails.last() = i;
         else
@@ -545,9 +537,9 @@ bool afxModel::onAdd()
     // Snag any "unmatched" LOS details
     static const String sLOSStr( "LOS-" );
 
-    for (U32 i = 0; i < mDataBlock->mShape->details.size(); i++)
+    for (U32 i = 0; i < mDataBlock->getShape()->details.size(); i++)
     {
-      const String &name = mDataBlock->mShape->names[mDataBlock->mShape->details[i].nameIndex];
+      const String &name = mDataBlock->getShape()->names[mDataBlock->getShape()->details[i].nameIndex];
 
       if (name.compare( sLOSStr, sLOSStr.length(), String::NoCase ) == 0)
       {

+ 10 - 9
Engine/source/afx/ce/afxModel.h

@@ -39,12 +39,11 @@ class TSShape;
 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 // afxModel Data
 
-struct afxModelData : public GameBaseData
+struct afxModelData : public GameBaseData, protected AssetPtrCallback
 {
   typedef GameBaseData Parent;
 
-  DECLARE_SHAPEASSET(afxModelData, Shape, onShapeChanged);
-  DECLARE_ASSET_SETGET(afxModelData, Shape);
+  DECLARE_SHAPEASSET_REFACTOR(afxModelData, Shape)
 
   StringTableEntry      sequence;
 
@@ -94,13 +93,15 @@ public:
 
   static void           initPersistFields();
 
-  void onShapeChanged()
-  {
-     reloadOnLocalClient();
-  }
   void onSequenceChanged() {}
 
   DECLARE_CONOBJECT(afxModelData);
+
+protected:
+   void onAssetRefreshed(AssetPtrBase* pAssetPtrBase) override
+   {
+      reloadOnLocalClient();
+   }
 };
 
 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
@@ -154,9 +155,9 @@ public:
   void                  setSequenceRateFactor(F32 factor);
   void                  setSortPriority(S8 priority) { sort_priority = priority; }
 
-  const char*           getShapeFileName() const { return mDataBlock->getShape(); }
+  const char*           getShapeFileName() const { return mDataBlock->getShapeFile(); }
   void                  setVisibility(bool flag) { is_visible = flag; }
-  TSShape*              getTSShape() { return mDataBlock->getShapeResource(); }
+  TSShape*              getTSShape() { return mDataBlock->getShape(); }
   TSShapeInstance*      getTSShapeInstance() { return shape_inst; }
 
   U32                   setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans);

+ 1 - 1
Engine/source/afx/ce/afxStaticShape.h

@@ -85,7 +85,7 @@ public:
   U32           packUpdate(NetConnection*, U32, BitStream*) override;
   void          unpackUpdate(NetConnection*, BitStream*) override;
 
-  const char*           getShapeFileName() const { return mDataBlock->mShapeAsset->getShapeFileName(); }
+  const char*           getShapeFileName() const { return mDataBlock->getShapeFile(); }
   void                  setVisibility(bool flag) { mIs_visible = flag; }
 
   DECLARE_CONOBJECT(afxStaticShape);

+ 15 - 17
Engine/source/environment/VolumetricFog.cpp

@@ -135,8 +135,6 @@ VolumetricFog::VolumetricFog()
    mTexTiles = 1.0f;
    mSpeed1.set(0.5f, 0.0f);
    mSpeed2.set(0.1f, 0.1f);
-
-   INIT_ASSET(Shape);
 }
 
 VolumetricFog::~VolumetricFog()
@@ -164,7 +162,7 @@ void VolumetricFog::initPersistFields()
    docsURL;
    Parent::initPersistFields();
    addGroup("Shapes");
-      INITPERSISTFIELD_SHAPEASSET(Shape, VolumetricFog, "The source shape asset.");
+      INITPERSISTFIELD_SHAPEASSET_REFACTOR(Shape, VolumetricFog, "The source shape asset.");
    endGroup("Shapes");
 
    addGroup("VolumetricFogData");
@@ -342,7 +340,7 @@ void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize)
 
 bool VolumetricFog::setShapeAsset(const StringTableEntry shapeAssetId)
 {
-   mShapeAssetId = shapeAssetId;
+   _setShape(shapeAssetId);
 
    LoadShape();
    return true;
@@ -358,20 +356,20 @@ bool VolumetricFog::LoadShape()
       return false;
    }
 
-   if (!mShape)
+   if (!getShape())
    {
       Con::errorf("VolumetricFog::_createShape() - Shape Asset had no valid shape!");
       return false;
    }
 
-   mObjBox = mShape->mBounds;
-   mRadius = mShape->mRadius;
+   mObjBox = getShape()->mBounds;
+   mRadius = getShape()->mRadius;
    resetWorldBox();
 
    if (!isClientObject())
       return false;
 
-   TSShapeInstance *mShapeInstance = new TSShapeInstance(mShape, false);
+   TSShapeInstance *mShapeInstance = new TSShapeInstance(getShape(), false);
    meshes mesh_detail;
 
    for (S32 i = 0; i < det_size.size(); i++)
@@ -387,9 +385,9 @@ bool VolumetricFog::LoadShape()
 
    // browsing model for detail levels
 
-   for (U32 i = 0; i < mShape->details.size(); i++)
+   for (U32 i = 0; i < getShape()->details.size(); i++)
    {
-      const TSDetail *detail = &mShape->details[i];
+      const TSDetail *detail = &getShape()->details[i];
       mesh_detail.det_size = detail->size;
       mesh_detail.sub_shape = detail->subShapeNum;
       mesh_detail.obj_det = detail->objectDetailNum;
@@ -405,8 +403,8 @@ bool VolumetricFog::LoadShape()
       const S32 ss = det_size[i].sub_shape;
       if (ss >= 0)
       {
-         const S32 start = mShape->subShapeFirstObject[ss];
-         const S32 end = start + mShape->subShapeNumObjects[ss];
+         const S32 start = getShape()->subShapeFirstObject[ss];
+         const S32 end = start + getShape()->subShapeNumObjects[ss];
          for (S32 j = start; j < end; j++)
          {
             // Loading shape, only the first mesh for each detail will be used!
@@ -568,7 +566,7 @@ U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
    }
    if (stream->writeFlag(mask & FogShapeMask))
    {
-      PACK_ASSET(con, Shape);
+      PACK_ASSET_REFACTOR(con, Shape);
       mathWrite(*stream, getTransform());
       mathWrite(*stream, getScale());
 
@@ -597,8 +595,8 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream)
    VectorF scale;
    VectorF mOldScale = getScale();
    StringTableEntry oldTextureName = mTextureAsset.getAssetId();
-   StringTableEntry oldShapeAsset = mShapeAssetId;
-   StringTableEntry oldShape = mShapeName;
+   StringTableEntry oldShapeAsset = _getShapeAssetId();
+   StringTableEntry oldShape = getShapeFile();
 
    if (stream->readFlag())// Fog color
       stream->read(&mFogColor);
@@ -667,11 +665,11 @@ void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream)
    }
    if (stream->readFlag())//Fog shape
    {
-      UNPACK_ASSET(con, Shape);
+      UNPACK_ASSET_REFACTOR(con, Shape);
 
       mathRead(*stream, &mat);
       mathRead(*stream, &scale);
-      if (strcmp(oldShapeAsset, mShapeAssetId) != 0 || strcmp(oldShape, mShapeName) != 0)
+      if (strcmp(oldShapeAsset, _getShapeAssetId()) != 0 || strcmp(oldShape, getShapeFile()) != 0)
       {
          mIsVBDirty = true;
          mShapeLoaded = LoadShape();

+ 2 - 4
Engine/source/environment/VolumetricFog.h

@@ -84,8 +84,7 @@ class VolumetricFog : public SceneObject
       Vector <U32> *indices;
    };
 
-   DECLARE_SHAPEASSET(VolumetricFog, Shape, onShapeChanged);
-   DECLARE_ASSET_NET_SETGET(VolumetricFog, Shape, FogShapeMask);
+   DECLARE_SHAPEASSET_REFACTOR(VolumetricFog, Shape)
    
    protected:
       // Rendertargets;
@@ -203,6 +202,7 @@ class VolumetricFog : public SceneObject
       void ResizeRT(PlatformWindow *win, bool resize);
    
    protected:
+
       // Protected methods
       bool onAdd() override;
       void onRemove() override;
@@ -246,8 +246,6 @@ class VolumetricFog : public SceneObject
       bool isInsideFog();
 
       bool setShapeAsset(const StringTableEntry shapeAssetId);
-
-      void onShapeChanged() {}
    
       DECLARE_CONOBJECT(VolumetricFog);
       DECLARE_CATEGORY("Environment \t Weather");