Browse Source

Merge pull request #723 from Areloch/MaterialAndTerrainMaterialPacking

Shifts handling of material and terrain material definitions to be written into the asset definition taml file instead of having an extra loose file
Brian Roberts 3 năm trước cách đây
mục cha
commit
68ae0ca96d
22 tập tin đã thay đổi với 1068 bổ sung338 xóa
  1. 2 2
      Engine/source/T3D/assets/ImageAsset.cpp
  2. 61 9
      Engine/source/T3D/assets/MaterialAsset.cpp
  3. 4 0
      Engine/source/T3D/assets/MaterialAsset.h
  4. 295 27
      Engine/source/T3D/assets/TerrainMaterialAsset.cpp
  5. 51 2
      Engine/source/T3D/assets/TerrainMaterialAsset.h
  6. 54 152
      Engine/source/T3D/assets/assetImporter.cpp
  7. 2 2
      Engine/source/assets/assetBase.h
  8. 2 2
      Engine/source/assets/assetDefinition.h
  9. 52 11
      Engine/source/console/simObject.cpp
  10. 5 0
      Engine/source/console/simObject.h
  11. 2 1
      Engine/source/materials/materialDefinition.cpp
  12. 30 8
      Engine/source/persistence/taml/taml.cpp
  13. 16 2
      Engine/source/persistence/taml/xml/tamlXmlReader.cpp
  14. 2 1
      Templates/BaseGame/game/tools/assetBrowser/assetImportConfigs.xml
  15. 0 1
      Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript
  16. 4 4
      Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript
  17. 28 30
      Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript
  18. 16 2
      Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript
  19. 253 46
      Templates/BaseGame/game/tools/projectImporter/importers/pre40/T3Dpre4ProjectImporter.tscript
  20. 1 1
      Templates/BaseGame/game/tools/projectImporter/importers/pre40/pre40ImporterGuis.tscript
  21. 185 14
      Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript
  22. 3 21
      Templates/BaseGame/game/tools/worldEditor/scripts/interfaces/terrainMaterialDlg.ed.tscript

+ 2 - 2
Engine/source/T3D/assets/ImageAsset.cpp

@@ -58,7 +58,7 @@ StringTableEntry ImageAsset::smNoImageAssetFallback = NULL;
 
 IMPLEMENT_CONOBJECT(ImageAsset);
 
-ConsoleType(ImageAssetPtr, TypeImageAssetPtr, const char*, ASSET_ID_FIELD_PREFIX)
+ConsoleType(ImageAssetPtr, TypeImageAssetPtr, const char*, "")
 
 //-----------------------------------------------------------------------------
 
@@ -85,7 +85,7 @@ ConsoleSetType(TypeImageAssetPtr)
    Con::warnf("(TypeImageAssetPtr) - Cannot set multiple args to a single asset.");
 }
 
-ConsoleType(assetIdString, TypeImageAssetId, const char*, ASSET_ID_FIELD_PREFIX)
+ConsoleType(assetIdString, TypeImageAssetId, const char*, "")
 
 ConsoleGetType(TypeImageAssetId)
 {

+ 61 - 9
Engine/source/T3D/assets/MaterialAsset.cpp

@@ -154,8 +154,9 @@ void MaterialAsset::initPersistFields()
    Parent::initPersistFields();
 
    //addField("shaderGraph", TypeRealString, Offset(mShaderGraphFile, MaterialAsset), "");
-   addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, MaterialAsset),
-      &setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
+   //addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, MaterialAsset),
+   //   &setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
+   addField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, MaterialAsset), "");
 
    addField("materialDefinitionName", TypeString, Offset(mMatDefinitionName, MaterialAsset), "Name of the material definition this asset is for.");
 }
@@ -173,7 +174,16 @@ void MaterialAsset::initializeAsset()
       return;
    }
 
-   if (Torque::FS::IsScriptFile(mScriptPath))
+   if (mMatDefinitionName == StringTable->insert("DetailBlue"))
+   {
+      bool asdfsd = true;
+   }
+
+   if (size() != 0 && mScriptPath == StringTable->EmptyString())
+   {
+      mLoadedState = EmbeddedDefinition;
+   }
+   else if (Torque::FS::IsScriptFile(mScriptPath))
    {
       if (!Sim::findObject(mMatDefinitionName))
       {
@@ -230,7 +240,6 @@ void MaterialAsset::setScriptFile(const char* pScriptFile)
    // Sanity!
    AssertFatal(pScriptFile != NULL, "Cannot use a NULL script file.");
 
-   // Fetch image file.
    pScriptFile = StringTable->insert(pScriptFile, true);
 
    // Update.
@@ -245,9 +254,28 @@ void MaterialAsset::setScriptFile(const char* pScriptFile)
 void MaterialAsset::loadMaterial()
 {
    if (mMaterialDefinition)
-      SAFE_DELETE(mMaterialDefinition);
+   {
+      mMaterialDefinition->safeDeleteObject();
+   }
 
-   if ((mLoadedState == ScriptLoaded || mLoadedState == DefinitionAlreadyExists) && mMatDefinitionName != StringTable->EmptyString())
+   if (mLoadedState == EmbeddedDefinition)
+   {
+      if (size() != 0)
+      {
+         for (U32 i = 0; i < size(); i++)
+         {
+            mMaterialDefinition = dynamic_cast<Material*>(getObject(i));
+            if (mMaterialDefinition)
+            {
+               mLoadedState = Ok;
+               mMaterialDefinition->setInternalName(getAssetId());
+               mMaterialDefinition->reload();
+               return;
+            }
+         }
+      }
+   }
+   else if ((mLoadedState == ScriptLoaded || mLoadedState == DefinitionAlreadyExists) && mMatDefinitionName != StringTable->EmptyString())
    {
       Material* matDef;
       if (!Sim::findObject(mMatDefinitionName, matDef))
@@ -260,7 +288,7 @@ void MaterialAsset::loadMaterial()
       mMaterialDefinition = matDef;
 
       mLoadedState = Ok;
-
+      mMaterialDefinition->setInternalName(getAssetId());
       mMaterialDefinition->reload();
       return;
    }
@@ -296,11 +324,11 @@ U32 MaterialAsset::getAssetByMaterialName(StringTableEntry matName, AssetPtr<Mat
       //handle noshape not being loaded itself
       if ((*matAsset)->mLoadedState == BadFileReference)
       {
-         Con::warnf("ShapeAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, and fallback asset reported error of Bad File Reference.", matName);
+         Con::warnf("MaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, and fallback asset reported error of Bad File Reference.", matName);
          return AssetErrCode::BadFileReference;
       }
 
-      Con::warnf("ShapeAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, utilizing fallback asset", matName);
+      Con::warnf("MaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, utilizing fallback asset", matName);
 
       (*matAsset)->mLoadedState = AssetErrCode::UsingFallback;
       return AssetErrCode::UsingFallback;
@@ -388,6 +416,17 @@ U32 MaterialAsset::getAssetById(StringTableEntry assetId, AssetPtr<MaterialAsset
    }
 }
 
+SimObjectPtr<Material> MaterialAsset::findMaterialDefinitionByAssetId(StringTableEntry assetId)
+{
+   SimSet* matSet = MATMGR->getMaterialSet();
+   if (matSet)
+   {
+      SimObjectPtr<Material> matDef = dynamic_cast<Material*>(matSet->findObjectByInternalName(assetId));
+      return matDef;
+   }
+   return nullptr;
+}
+
 #ifdef TORQUE_TOOLS
 DefineEngineStaticMethod(MaterialAsset, getAssetIdByMaterialName, const char*, (const char* materialName), (""),
    "Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
@@ -396,6 +435,19 @@ DefineEngineStaticMethod(MaterialAsset, getAssetIdByMaterialName, const char*, (
    return MaterialAsset::getAssetIdByMaterialName(StringTable->insert(materialName));
 }
 
+//MaterialAsset::findMaterialDefinitionByAssetId("Prototyping:Detail")
+DefineEngineStaticMethod(MaterialAsset, findMaterialDefinitionByAssetId, S32, (const char* assetId), (""),
+   "Queries the MaterialSet to see if any MaterialDefinition exists that is associated to the provided assetId.\n"
+   "@return The MaterialDefinition Id associated to the assetId, if any")
+{
+   SimObjectPtr<Material> matDef = MaterialAsset::findMaterialDefinitionByAssetId(StringTable->insert(assetId));
+   if (matDef.isNull())
+      return SimObjectId(0);
+   else
+      return matDef->getId();
+}
+
+
 DefineEngineMethod(MaterialAsset, getScriptPath, const char*, (), ,
    "Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
    "@return The AssetId of the associated asset, if any.")

+ 4 - 0
Engine/source/T3D/assets/MaterialAsset.h

@@ -48,7 +48,9 @@
 #include "sim/netConnection.h"
 #endif
 
+#ifndef _GUI_INSPECTOR_TYPES_H_
 #include "gui/editor/guiInspectorTypes.h"
+#endif
 
 #include "materials/matTextureTarget.h"
 #include "materials/materialDefinition.h"
@@ -75,6 +77,7 @@ public:
    {
       ScriptLoaded = AssetErrCode::Extended,
       DefinitionAlreadyExists,
+      EmbeddedDefinition,
       Extended
    };
 
@@ -108,6 +111,7 @@ public:
    /// <returns>AssetId of matching asset.</returns>
    static StringTableEntry getAssetIdByMaterialName(StringTableEntry matName);
    static U32 getAssetById(StringTableEntry assetId, AssetPtr<MaterialAsset>* materialAsset);
+   static SimObjectPtr<Material> findMaterialDefinitionByAssetId(StringTableEntry assetId);
    static U32 getAssetByMaterialName(StringTableEntry matName, AssetPtr<MaterialAsset>* matAsset);
 
    /// Declare Console Object.

+ 295 - 27
Engine/source/T3D/assets/TerrainMaterialAsset.cpp

@@ -40,6 +40,10 @@
 #include "assets/assetPtr.h"
 #endif
 
+#include "T3D/assets/assetImporter.h"
+
+StringTableEntry TerrainMaterialAsset::smNoTerrainMaterialAssetFallback = NULL;
+
 //-----------------------------------------------------------------------------
 
 IMPLEMENT_CONOBJECT(TerrainMaterialAsset);
@@ -85,6 +89,35 @@ ConsoleSetType(TypeTerrainMaterialAssetPtr)
    Con::warnf("(TypeTerrainMaterialAssetPtr) - Cannot set multiple args to a single asset.");
 }
 
+
+ConsoleType(assetIdString, TypeTerrainMaterialAssetId, const char*, ASSET_ID_FIELD_PREFIX)
+
+ConsoleGetType(TypeTerrainMaterialAssetId)
+{
+   // Fetch asset Id.
+   return *((const char**)(dptr));
+}
+
+ConsoleSetType(TypeTerrainMaterialAssetId)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset Id.
+      StringTableEntry* assetId = (StringTableEntry*)(dptr);
+
+      // Update asset value.
+      *assetId = StringTable->insert(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeTerrainMaterialAssetId) - Cannot set multiple args to a single asset.");
+}
 //-----------------------------------------------------------------------------
 
 TerrainMaterialAsset::TerrainMaterialAsset()
@@ -92,24 +125,41 @@ TerrainMaterialAsset::TerrainMaterialAsset()
    mScriptFile = StringTable->EmptyString();
    mScriptPath = StringTable->EmptyString();
    mMatDefinitionName = StringTable->EmptyString();
+   mMaterialDefinition = nullptr;
+   mFXMaterialDefinition = nullptr;
 }
 
 //-----------------------------------------------------------------------------
 
 TerrainMaterialAsset::~TerrainMaterialAsset()
 {
+   if (mMaterialDefinition)
+      mMaterialDefinition->safeDeleteObject();
+   if (mFXMaterialDefinition)
+      mFXMaterialDefinition->safeDeleteObject();
 }
 
 //-----------------------------------------------------------------------------
 
+void TerrainMaterialAsset::consoleInit()
+{
+   Parent::consoleInit();
+   Con::addVariable("$Core::NoTerrainMaterialAssetFallback", TypeString, &smNoTerrainMaterialAssetFallback,
+      "The assetId of the material to display when the requested material asset is missing.\n"
+      "@ingroup GFX\n");
+   
+   smNoTerrainMaterialAssetFallback = StringTable->insert(Con::getVariable("$Core::NoTerrainMaterialAssetFallback"));
+}
+
 void TerrainMaterialAsset::initPersistFields()
 {
    // Call parent.
    Parent::initPersistFields();
 
    //addField("shaderGraph", TypeRealString, Offset(mShaderGraphFile, TerrainMaterialAsset), "");
-   addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, TerrainMaterialAsset),
-      &setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
+   //addProtectedField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, TerrainMaterialAsset),
+   //   &setScriptFile, &getScriptFile, "Path to the file containing the material definition.");
+   addField("scriptFile", TypeAssetLooseFilePath, Offset(mScriptFile, TerrainMaterialAsset), "");
 
    addField("materialDefinitionName", TypeString, Offset(mMatDefinitionName, TerrainMaterialAsset), "Name of the material definition this asset is for.");
 }
@@ -121,28 +171,71 @@ void TerrainMaterialAsset::initializeAsset()
 
    mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
 
-   if (Torque::FS::IsScriptFile(mScriptPath))
-      Con::executeFile(mScriptPath, false, false);
+   if (mMatDefinitionName == StringTable->EmptyString())
+   {
+      mLoadedState = Failed;
+      return;
+   }
+
+   if (mMatDefinitionName == StringTable->insert("DetailBlue"))
+   {
+      bool asdfsd = true;
+   }
+
+   if (size() != 0 && mScriptPath == StringTable->EmptyString())
+   {
+      mLoadedState = EmbeddedDefinition;
+   }
+   else if (Torque::FS::IsScriptFile(mScriptPath))
+   {
+      if (!Sim::findObject(mMatDefinitionName))
+      {
+          if (Con::executeFile(mScriptPath, false, false))
+          {
+              mLoadedState = ScriptLoaded;
+          }
+          else
+          {
+              mLoadedState = Failed;
+          }
+      }
+      else
+      {
+         mLoadedState = DefinitionAlreadyExists;
+      }
+   }
+
+   loadMaterial();
 }
 
 void TerrainMaterialAsset::onAssetRefresh()
 {
    mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath;
 
-   if (Torque::FS::IsScriptFile(mScriptPath))
-      Con::executeFile(mScriptPath, false, false);
-
-   if (mMatDefinitionName != StringTable->EmptyString())
+   if (mMatDefinitionName == StringTable->EmptyString())
    {
-      TerrainMaterial* matDef;
-      if (!Sim::findObject(mMatDefinitionName, matDef))
-      {
-         Con::errorf("TerrainMaterialAsset: Unable to find the Material %s", mMatDefinitionName);
+      mLoadedState = Failed;
          return;
       }
 
-      //matDef->reload();
+   if (Torque::FS::IsScriptFile(mScriptPath))
+   {
+      //Since we're refreshing, we can assume that the file we're executing WILL have an existing definition.
+      //But that definition, whatever it is, is the 'correct' one, so we enable the Replace Existing behavior
+      //when the engine encounters a named object conflict.
+      String redefineBehaviorPrev = Con::getVariable("$Con::redefineBehavior");
+      Con::setVariable("$Con::redefineBehavior", "replaceExisting");
+
+      if (Con::executeFile(mScriptPath, false, false))
+         mLoadedState = ScriptLoaded;
+      else
+         mLoadedState = Failed;
+
+      //And now that we've executed, switch back to the prior behavior
+      Con::setVariable("$Con::redefineBehavior", redefineBehaviorPrev.c_str());
    }
+
+   loadMaterial();
 }
 
 void TerrainMaterialAsset::setScriptFile(const char* pScriptFile)
@@ -152,10 +245,6 @@ void TerrainMaterialAsset::setScriptFile(const char* pScriptFile)
 
    pScriptFile = StringTable->insert(pScriptFile, true);
 
-   // Ignore no change,
-   if (pScriptFile == mScriptFile)
-      return;
-
    // Update.
    mScriptFile = getOwned() ? expandAssetFilePath(pScriptFile) : pScriptFile;
 
@@ -165,41 +254,185 @@ void TerrainMaterialAsset::setScriptFile(const char* pScriptFile)
 
 //------------------------------------------------------------------------------
 
+void TerrainMaterialAsset::loadMaterial()
+{
+   if (mMaterialDefinition)
+      mMaterialDefinition->safeDeleteObject();
+   if (mFXMaterialDefinition)
+      mFXMaterialDefinition->safeDeleteObject();
+
+   if (mLoadedState == EmbeddedDefinition)
+   {
+      if (size() != 0)
+      {
+         for (U32 i = 0; i < size(); i++)
+         {
+            mMaterialDefinition = dynamic_cast<TerrainMaterial*>(getObject(i));
+            if (mMaterialDefinition)
+            {
+               mLoadedState = Ok;
+               mMaterialDefinition->setInternalName(getAssetId());
+               continue;
+            }
+
+            //Otherwise, check if it's our FX material
+            mFXMaterialDefinition = dynamic_cast<Material*>(getObject(i));
+            if (mFXMaterialDefinition)
+            {
+               //mMaterialDefinition->setInternalName(getAssetId());
+               mFXMaterialDefinition->reload();
+               continue;
+            }
+
+         }
+      }
+   }
+   else if ((mLoadedState == ScriptLoaded || mLoadedState == DefinitionAlreadyExists) && mMatDefinitionName != StringTable->EmptyString())
+   {
+      TerrainMaterial* matDef;
+      if (!Sim::findObject(mMatDefinitionName, matDef))
+      {
+         Con::errorf("TerrainMaterialAsset: Unable to find the Material %s", mMatDefinitionName);
+         mLoadedState = BadFileReference;
+         return;
+      }
+
+      mMaterialDefinition = matDef;
+
+      mLoadedState = Ok;
+      mMaterialDefinition->setInternalName(getAssetId());
+      return;
+   }
+
+   mLoadedState = Failed;
+}
+
+//------------------------------------------------------------------------------
+
 void TerrainMaterialAsset::copyTo(SimObject* object)
 {
    // Call to parent.
    Parent::copyTo(object);
 }
 
-StringTableEntry TerrainMaterialAsset::getAssetIdByMaterialName(StringTableEntry matName)
+//------------------------------------------------------------------------------
+U32 TerrainMaterialAsset::getAssetByMaterialName(StringTableEntry matName, AssetPtr<TerrainMaterialAsset>* matAsset)
 {
-   StringTableEntry materialAssetId = StringTable->EmptyString();
-
-   AssetQuery* query = new AssetQuery();
-   U32 foundCount = AssetDatabase.findAssetType(query, "TerrainMaterialAsset");
-   if (foundCount == 0)
+   AssetQuery query;
+   U32 foundAssetcount = AssetDatabase.findAssetType(&query, "TerrainMaterialAsset");
+   if (foundAssetcount == 0)
    {
       //Didn't work, so have us fall back to a placeholder asset
-      materialAssetId = StringTable->insert("Core_Rendering:noMaterial");
+      matAsset->setAssetId(TerrainMaterialAsset::smNoTerrainMaterialAssetFallback);
+
+      if (matAsset->isNull())
+      {
+         //Well that's bad, loading the fallback failed.
+         Con::warnf("TerrainMaterialAsset::getAssetByMaterialName - Finding of asset associated with material name %s failed with no fallback asset", matName);
+         return AssetErrCode::Failed;
+      }
+
+      //handle noshape not being loaded itself
+      if ((*matAsset)->mLoadedState == BadFileReference)
+      {
+         Con::warnf("TerrainMaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, and fallback asset reported error of Bad File Reference.", matName);
+         return AssetErrCode::BadFileReference;
+      }
+
+      Con::warnf("TerrainMaterialAsset::getAssetByMaterialName - Finding of associated with aterial name %s failed, utilizing fallback asset", matName);
+
+      (*matAsset)->mLoadedState = AssetErrCode::UsingFallback;
+      return AssetErrCode::UsingFallback;
    }
    else
+   {
+      for (U32 i = 0; i < foundAssetcount; i++)
+      {
+         TerrainMaterialAsset* tMatAsset = AssetDatabase.acquireAsset<TerrainMaterialAsset>(query.mAssetList[i]);
+         if (tMatAsset && tMatAsset->getMaterialDefinitionName() == matName)
+         {
+            matAsset->setAssetId(query.mAssetList[i]);
+            AssetDatabase.releaseAsset(query.mAssetList[i]);
+            return (*matAsset)->mLoadedState;
+         }
+         AssetDatabase.releaseAsset(query.mAssetList[i]); //cleanup if that's not the one we needed
+      }
+   }
+
+   //Somehow we failed to bind an asset, so just use the fallback and mark the failure
+   matAsset->setAssetId(TerrainMaterialAsset::smNoTerrainMaterialAssetFallback);
+   (*matAsset)->mLoadedState = AssetErrCode::UsingFallback;
+   return AssetErrCode::UsingFallback;
+
+}
+
+StringTableEntry TerrainMaterialAsset::getAssetIdByMaterialName(StringTableEntry matName)
+{
+   if (matName == StringTable->EmptyString())
+      return StringTable->EmptyString();
+
+   StringTableEntry materialAssetId = TerrainMaterialAsset::smNoTerrainMaterialAssetFallback;
+
+   AssetQuery query;
+   U32 foundCount = AssetDatabase.findAssetType(&query, "TerrainMaterialAsset");
+   if (foundCount != 0)
    {
       for (U32 i = 0; i < foundCount; i++)
       {
-         TerrainMaterialAsset* matAsset = AssetDatabase.acquireAsset<TerrainMaterialAsset>(query->mAssetList[i]);
+         TerrainMaterialAsset* matAsset = AssetDatabase.acquireAsset<TerrainMaterialAsset>(query.mAssetList[i]);
          if (matAsset && matAsset->getMaterialDefinitionName() == matName)
          {
             materialAssetId = matAsset->getAssetId();
-            AssetDatabase.releaseAsset(query->mAssetList[i]);
+            AssetDatabase.releaseAsset(query.mAssetList[i]);
             break;
          }
-         AssetDatabase.releaseAsset(query->mAssetList[i]);
+         AssetDatabase.releaseAsset(query.mAssetList[i]);
       }
    }
 
    return materialAssetId;
 }
 
+U32 TerrainMaterialAsset::getAssetById(StringTableEntry assetId, AssetPtr<TerrainMaterialAsset>* materialAsset)
+{
+   (*materialAsset) = assetId;
+   if (materialAsset->notNull())
+   {
+      return (*materialAsset)->mLoadedState;
+   }
+   else
+   {
+      //Didn't work, so have us fall back to a placeholder asset
+      materialAsset->setAssetId(TerrainMaterialAsset::smNoTerrainMaterialAssetFallback);
+      if (materialAsset->isNull())
+      {
+         //Well that's bad, loading the fallback failed.
+         Con::warnf("TerrainMaterialAsset::getAssetById - Finding of asset with id %s failed with no fallback asset", assetId);
+         return AssetErrCode::Failed;
+      }
+      //handle noshape not being loaded itself
+      if ((*materialAsset)->mLoadedState == BadFileReference)
+      {
+         Con::warnf("TerrainMaterialAsset::getAssetById - Finding of asset with id %s failed, and fallback asset reported error of Bad File Reference.", assetId);
+         return AssetErrCode::BadFileReference;
+      }
+      Con::warnf("TerrainMaterialAsset::getAssetById - Finding of asset with id %s failed, utilizing fallback asset", assetId);
+      (*materialAsset)->mLoadedState = AssetErrCode::UsingFallback;
+      return AssetErrCode::UsingFallback;
+   }
+}
+SimObjectPtr<TerrainMaterial> TerrainMaterialAsset::findMaterialDefinitionByAssetId(StringTableEntry assetId)
+{
+   SimSet* terrainMatSet;
+   if (!Sim::findObject("TerrainMaterialSet", terrainMatSet))
+   {
+      return nullptr;
+   }
+
+   SimObjectPtr<TerrainMaterial> matDef = dynamic_cast<TerrainMaterial*>(terrainMatSet->findObjectByInternalName(assetId));
+   return matDef;
+}
+
 #ifdef TORQUE_TOOLS
 DefineEngineStaticMethod(TerrainMaterialAsset, getAssetIdByMaterialName, const char*, (const char* materialName), (""),
    "Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
@@ -207,6 +440,26 @@ DefineEngineStaticMethod(TerrainMaterialAsset, getAssetIdByMaterialName, const c
 {
    return TerrainMaterialAsset::getAssetIdByMaterialName(StringTable->insert(materialName));
 }
+
+//MaterialAsset::findMaterialDefinitionByAssetId("Prototyping:Detail")
+DefineEngineStaticMethod(TerrainMaterialAsset, findMaterialDefinitionByAssetId, S32, (const char* assetId), (""),
+   "Queries the MaterialSet to see if any MaterialDefinition exists that is associated to the provided assetId.\n"
+   "@return The MaterialDefinition Id associated to the assetId, if any")
+{
+   SimObjectPtr<TerrainMaterial> matDef = TerrainMaterialAsset::findMaterialDefinitionByAssetId(StringTable->insert(assetId));
+   if (matDef.isNull())
+      return SimObjectId(0);
+   else
+      return matDef->getId();
+}
+
+
+DefineEngineMethod(TerrainMaterialAsset, getScriptPath, const char*, (), ,
+   "Queries the Asset Database to see if any asset exists that is associated with the provided material name.\n"
+   "@return The AssetId of the associated asset, if any.")
+{
+   return object->getScriptPath();
+}
 #endif
 //-----------------------------------------------------------------------------
 // GuiInspectorTypeAssetId
@@ -343,3 +596,18 @@ DefineEngineMethod(GuiInspectorTypeTerrainMaterialAssetPtr, setMaterialAsset, vo
 
    return object->setMaterialAsset(assetId);
 }
+
+IMPLEMENT_CONOBJECT(GuiInspectorTypeTerrainMaterialAssetId);
+
+ConsoleDocClass(GuiInspectorTypeTerrainMaterialAssetId,
+   "@brief Inspector field type for Terrain Material Assets\n\n"
+   "Editor use only.\n\n"
+   "@internal"
+);
+
+void GuiInspectorTypeTerrainMaterialAssetId::consoleInit()
+{
+   Parent::consoleInit();
+
+   ConsoleBaseType::getType(TypeTerrainMaterialAssetId)->setInspectorFieldType("GuiInspectorTypeTerrainMaterialAssetId");
+}

+ 51 - 2
Engine/source/T3D/assets/TerrainMaterialAsset.h

@@ -47,7 +47,13 @@
 #include "gui/editor/guiInspectorTypes.h"
 #endif
 
+#ifndef _TERRMATERIAL_H_
 #include "terrain/terrMaterial.h"
+#endif
+
+#ifndef _MATERIALDEFINITION_H_
+#include "materials/materialDefinition.h"
+#endif
 
 //-----------------------------------------------------------------------------
 class TerrainMaterialAsset : public AssetBase
@@ -58,23 +64,53 @@ class TerrainMaterialAsset : public AssetBase
    StringTableEntry        mScriptPath;
    StringTableEntry        mMatDefinitionName;
 
+   SimObjectPtr<TerrainMaterial>  mMaterialDefinition;
+
+   SimObjectPtr<Material>  mFXMaterialDefinition;
+
+public:
+   static StringTableEntry smNoTerrainMaterialAssetFallback;
+   
+   enum TerrainMaterialAssetErrCode
+   {
+      ScriptLoaded = AssetErrCode::Extended,
+      DefinitionAlreadyExists,
+      EmbeddedDefinition,
+      Extended
+   };
+
 public:
    TerrainMaterialAsset();
    virtual ~TerrainMaterialAsset();
+   /// Set up some global script interface stuff.
+   static void consoleInit();
 
    /// Engine.
    static void initPersistFields();
    virtual void copyTo(SimObject* object);
 
-   static StringTableEntry getAssetIdByMaterialName(StringTableEntry matName);
+   void loadMaterial();
 
    StringTableEntry getMaterialDefinitionName() { return mMatDefinitionName; }
+   SimObjectPtr<TerrainMaterial> getMaterialDefinition() { return mMaterialDefinition; }
 
    void                    setScriptFile(const char* pScriptFile);
    inline StringTableEntry getScriptFile(void) const { return mScriptFile; };
 
    inline StringTableEntry getScriptPath(void) const { return mScriptPath; };
 
+   /// <summary>
+   /// Looks for any assets that uses the provided Material Definition name.
+   /// If none are found, attempts to auto-import the material definition if the
+   /// material definition exists.
+   /// </summary>
+   /// <param name="matName">Material Definition name to look for</param>
+   /// <returns>AssetId of matching asset.</returns>
+   static StringTableEntry getAssetIdByMaterialName(StringTableEntry matName);
+   static U32 getAssetById(StringTableEntry assetId, AssetPtr<TerrainMaterialAsset>* materialAsset);
+   static SimObjectPtr<TerrainMaterial> findMaterialDefinitionByAssetId(StringTableEntry assetId);
+   static U32 getAssetByMaterialName(StringTableEntry matName, AssetPtr<TerrainMaterialAsset>* matAsset);
+
    /// Declare Console Object.
    DECLARE_CONOBJECT(TerrainMaterialAsset);
 
@@ -82,11 +118,16 @@ protected:
    virtual void initializeAsset();
    virtual void onAssetRefresh(void);
 
-   static bool setScriptFile(void *obj, const char *index, const char *data) { static_cast<TerrainMaterialAsset*>(obj)->setScriptFile(data); return false; }
+   static bool setScriptFile(void *obj, const char *index, const char *data) 
+   { 
+	   static_cast<TerrainMaterialAsset*>(obj)->setScriptFile(data); 
+	   return false; 
+   }
    static const char* getScriptFile(void* obj, const char* data) { return static_cast<TerrainMaterialAsset*>(obj)->getScriptFile(); }
 };
 
 DefineConsoleType(TypeTerrainMaterialAssetPtr, TerrainMaterialAsset)
+DefineConsoleType(TypeMaterialAssetId, String)
 
 //-----------------------------------------------------------------------------
 // TypeAssetId GuiInspectorField Class
@@ -107,6 +148,14 @@ public:
    virtual bool updateRects();
    void setMaterialAsset(String assetId);
 };
+class GuiInspectorTypeTerrainMaterialAssetId : public GuiInspectorTypeTerrainMaterialAssetPtr
+{
+   typedef GuiInspectorTypeTerrainMaterialAssetPtr Parent;
+public:
+
+   DECLARE_CONOBJECT(GuiInspectorTypeTerrainMaterialAssetId);
+   static void consoleInit();
+};
 
 #endif // _ASSET_BASE_H_
 

+ 54 - 152
Engine/source/T3D/assets/assetImporter.cpp

@@ -609,14 +609,32 @@ AssetImportObject* AssetImporter::addImportingAsset(String assetType, Torque::Pa
    assetImportObj->registerObject();
 
    //sanitize
-   assetName.replace(' ', '_');
-   assetName.replace('~', '_');
-   assetName.replace('`', '_');
-   assetName.replace('-', '_');
-   assetName.replace('*', '_');
-   assetName.replace('-', '_');
-   assetName.replace('+', '_');
-   assetName.replace('&', '_');
+   String processedString = assetName;
+
+   U32 start;
+   U32 end;
+   String firstNumber = String::GetFirstNumber(processedString, start, end);
+   if (!firstNumber.isEmpty() && processedString.startsWith(firstNumber.c_str()))
+      processedString = processedString.replace(firstNumber, "");
+
+   processedString = processedString.replace(" ", "_");
+
+   U32 len = processedString.length() + 1;
+   char* sanitizedStr = Con::getReturnBuffer(len);
+   dStrcpy(sanitizedStr, processedString.c_str(), len);
+
+   U32 pos = dStrcspn(sanitizedStr, "-+*/%$&�=()[].?\\\"#,;!~<>|�^{}");
+   while (pos < dStrlen(sanitizedStr))
+   {
+      dStrcpy(sanitizedStr + pos, sanitizedStr + pos + 1, len - pos);
+      pos = dStrcspn(sanitizedStr, "-+*/%$&�=()[].?\\\"#,;!~<>|�^{}");
+   }
+
+   //If we did, indeed, modify the name, update it now
+   if (String(sanitizedStr) != assetName)
+   {
+      assetName = sanitizedStr;
+   }
 
    assetImportObj->assetType = assetType;
    assetImportObj->filePath = filePath;
@@ -2725,8 +2743,6 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
    StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
 
    String tamlPath = targetPath + "/" + assetName + ".asset.taml";
-   String scriptName = assetItem->assetName + "." TORQUE_SCRIPT_EXTENSION;
-   String scriptPath = targetPath + "/" + scriptName;
    String originalPath = assetItem->filePath.getFullPath().c_str();
 
    char qualifiedFromFile[2048];
@@ -2734,10 +2750,8 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
    Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
 
    newAsset->setAssetName(assetName);
-   newAsset->setScriptFile(scriptName.c_str());
    newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
    newAsset->setDataField(StringTable->insert("materialDefinitionName"), nullptr, assetName);
-   
 
    //iterate through and write out the material maps dependencies
    S32 dependencySlotId = 0;
@@ -2759,16 +2773,6 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
       dependencySlotId++;
    }
 
-   Taml tamlWriter;
-   bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
-
-   if (!importSuccessful)
-   {
-      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
-      activityLog.push_back(importLogBuffer);
-      return "";
-   }
-
    //build the ORMConfig file if we're flagged to and have valid image maps
    if (activeImportConfig->CreateORMConfig)
    {
@@ -2807,109 +2811,12 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
       }
    }
 
-   FileObject* file = new FileObject();
-   file->registerObject();
-
-   if (activeImportConfig->UseExistingMaterials && Platform::isFile(qualifiedFromFile))
+   //If we're not using existing materials, or the material in question doesn't actually already exist, spool it up
+   if (!activeImportConfig->UseExistingMaterials || !Sim::findObject(assetName))
    {
-      //Now write the script file containing our material out
-      //There's 2 ways to do this. If we're in-place importing an existing asset, we can see if the definition existed already, like in an old
-      //materials.tscript file. if it does, we can just find the object by name, and save it out to our new file
-      //If not, we'll just generate one
-      Material* existingMat = MATMGR->getMaterialDefinitionByName(assetName);
-
-      //It's also possible that, for legacy models, the material hooks in via the material's mapTo field, and the material name is something completely different
-      //So we'll check for that as well if we didn't find it by name up above
-      if (existingMat == nullptr)
-         existingMat = MATMGR->getMaterialDefinitionByMapTo(assetName);
-
-      if (existingMat == nullptr && assetItem->assetName != assetItem->cleanAssetName)
-      {
-         existingMat = MATMGR->getMaterialDefinitionByName(assetItem->cleanAssetName);
-         if (existingMat == nullptr)
-            existingMat = MATMGR->getMaterialDefinitionByMapTo(assetItem->cleanAssetName);
-      }
-
-      if (existingMat)
-      {
-         PersistenceManager* persistMgr;
-         if (Sim::findObject("ImageAssetValidator", persistMgr))
-         {
-            for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
-            {
-               AssetImportObject* childItem = assetItem->childAssetItems[i];
-
-               if (childItem->canImport() || childItem->assetType.compare("ImageAsset") != 0)
-                  continue;
-
-               String path = childItem->filePath.getFullFileName();
-
-               String mapFieldName = "";
-               String assetFieldName = "";
-
-               ImageAsset::ImageTypes imageType = ImageAsset::getImageTypeFromName(childItem->imageSuffixType);
-
-               if (imageType == ImageAsset::ImageTypes::Albedo || childItem->imageSuffixType.isEmpty())
-               {
-                  mapFieldName = "DiffuseMap";
-               }
-               else if (imageType == ImageAsset::ImageTypes::Normal)
-               {
-                  mapFieldName = "NormalMap";
-               }
-               else if (imageType == ImageAsset::ImageTypes::ORMConfig)
-               {
-                  mapFieldName = "ORMConfig";
-               }
-               else if (imageType == ImageAsset::ImageTypes::Metalness)
-               {
-                  mapFieldName = "MetalMap";
-               }
-               else if (imageType == ImageAsset::ImageTypes::AO)
-               {
-                  mapFieldName = "AOMap";
-               }
-               else if (imageType == ImageAsset::ImageTypes::Roughness)
-               {
-                  mapFieldName = "RoughMap";
-               }
-
-               assetFieldName = mapFieldName + "Asset[0]";
-               mapFieldName += "[0]";
-
-               //If there's already an existing image map file on the material definition in this slot, don't override it
-               if (!path.isEmpty())
-                  existingMat->writeField(mapFieldName.c_str(), path.c_str());
-
-               String targetAsset = targetModuleId + ":" + childItem->assetName;
-
-               existingMat->writeField(assetFieldName.c_str(), targetAsset.c_str());
-            }
-
-            persistMgr->setDirty(existingMat);
-         }
-         else
-         {
-            Con::errorf("ImageAssetValidator not found!");
-         }
-      }
-      else
-      {
-         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Failed to find original material definition %s!", assetName);
-         activityLog.push_back(importLogBuffer);
-         return tamlPath;
-      }
-   }
-   else if (file->openForWrite(scriptPath.c_str()))
-   {
-      file->writeLine((U8*)"//--- OBJECT WRITE BEGIN ---");
-
-      char lineBuffer[1024];
-      dSprintf(lineBuffer, 1024, "singleton Material(%s) {", assetName);
-      file->writeLine((U8*)lineBuffer);
-
-      dSprintf(lineBuffer, 1024, "   mapTo=\"%s\";", assetName);
-      file->writeLine((U8*)lineBuffer);
+      Material* newMat = new Material();
+      newMat->registerObject(assetName);
+      newMat->mMapTo = assetName;
 
       bool hasRoughness = false;
       for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
@@ -2919,63 +2826,58 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
          if ((!childItem->canImport() && childItem->importStatus != AssetImportObject::UseForDependencies) || childItem->assetType.compare("ImageAsset") != 0)
             continue;
 
-         String mapFieldName = "";
-
-         String assetFieldName = "";
-
          ImageAsset::ImageTypes imageType = ImageAsset::getImageTypeFromName(childItem->imageSuffixType);
 
+         String assetMapFillIn = targetModuleId + ":" + childItem->assetName;
+         StringTableEntry assetMapFillInStr = StringTable->insert(assetMapFillIn.c_str());
+
          if (imageType == ImageAsset::ImageTypes::Albedo || childItem->imageSuffixType.isEmpty())
          {
-            mapFieldName = "DiffuseMap";
+            newMat->mDiffuseMapAssetId[0] = assetMapFillInStr;
          }
          else if (imageType == ImageAsset::ImageTypes::Normal)
          {
-            mapFieldName = "NormalMap";
+            newMat->mNormalMapAssetId[0] = assetMapFillInStr;
          }
          else if (imageType == ImageAsset::ImageTypes::ORMConfig)
          {
-            mapFieldName = "ORMConfigMap";
+            newMat->mORMConfigMapAssetId[0] = assetMapFillInStr;
          }
          else if (imageType == ImageAsset::ImageTypes::Metalness)
          {
-            mapFieldName = "MetalMap";
+            newMat->mMetalMapAssetId[0] = assetMapFillInStr;
          }
          else if (imageType == ImageAsset::ImageTypes::AO)
          {
-            mapFieldName = "AOMap";
+            newMat->mAOMapAssetId[0] = assetMapFillInStr;
          }
          else if (imageType == ImageAsset::ImageTypes::Roughness)
          {
-            mapFieldName = "RoughMap";
+            newMat->mRoughMapAssetId[0] = assetMapFillInStr;
             hasRoughness = true;
          }
-
-         assetFieldName = mapFieldName + "Asset";
-         assetFieldName += "[0]";
-
-         //String path = childItem->filePath.getFullFileName();
-         //dSprintf(lineBuffer, 1024, "   %s = \"%s\";", mapFieldName.c_str(), path.c_str());
-         //file->writeLine((U8*)lineBuffer);
-
-         dSprintf(lineBuffer, 1024, "   %s = \"%s:%s\";", assetFieldName.c_str(), targetModuleId.c_str(), childItem->assetName.c_str());
-         file->writeLine((U8*)lineBuffer);
       }
 
       if (hasRoughness)
       {
-         file->writeLine((U8*)"   invertSmoothness = true;");
-         
+         newMat->mInvertRoughness[0] = true;
       }
 
-      file->writeLine((U8*)"};");
-      file->writeLine((U8*)"//--- OBJECT WRITE END ---");
-
-      file->close();
+      newAsset->addObject(newMat);
    }
-   else
+   else 
    {
-      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset script file %s", scriptPath.c_str());
+      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Set to use an existing material, so avoiding writing a material definition to new asset definition for material: %s", assetName);
+      activityLog.push_back(importLogBuffer);
+      return "";
+   }
+
+   Taml tamlWriter;
+   bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
+
+   if (!importSuccessful)
+   {
+      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
       activityLog.push_back(importLogBuffer);
       return "";
    }

+ 2 - 2
Engine/source/assets/assetBase.h

@@ -55,11 +55,11 @@ extern StringTableEntry assetAutoUnloadField;
 //#define ASSET_BASE_AUTOUNLOAD_FIELD        "AssetAutoUnload"
 
 //-----------------------------------------------------------------------------
-class AssetBase : public SimObject
+class AssetBase : public SimGroup
 {
    friend class AssetManager;
 
-   typedef SimObject Parent;
+   typedef SimGroup Parent;
 
 protected:
    AssetManager*           mpOwningAssetManager;

+ 2 - 2
Engine/source/assets/assetDefinition.h

@@ -35,8 +35,8 @@
 #include "console/sim.h"
 #endif
 
-#ifndef _SIMOBJECT_H_
-#include "console/simObject.h"
+#ifndef _SIMSET_H_
+#include "console/simset.h"
 #endif
 
 #ifndef _CONSOLEOBJECT_H_

+ 52 - 11
Engine/source/console/simObject.cpp

@@ -77,6 +77,7 @@ SimObject::SimObject()
    mObjectName = NULL;
    mOriginalName         = NULL;
    mInternalName         = NULL;
+   mInheritFrom          = NULL;
    nextNameObject        = nullptr;
    nextManagerNameObject = nullptr;
    nextIdObject          = NULL;
@@ -154,6 +155,9 @@ void SimObject::initPersistFields()
 
       addProtectedField( "name", TypeName, Offset(mObjectName, SimObject), &setProtectedName, &defaultProtectedGetFn,
          "Optional global name of this object." );
+
+      addProtectedField("inheritFrom", TypeString, Offset(mInheritFrom, SimObject), &setInheritFrom, &defaultProtectedGetFn,
+         "Optional Name of object to inherit from as a parent.");
                   
    endGroup( "Ungrouped" );
 
@@ -300,6 +304,10 @@ bool SimObject::writeField(StringTableEntry fieldname, const char* value)
 void SimObject::writeFields(Stream &stream, U32 tabStop)
 {
    // Write static fields.
+
+   // Create a default object of the same type
+   ConsoleObject* defaultConObject = ConsoleObject::create(getClassName());
+   SimObject* defaultObject = dynamic_cast<SimObject*>(defaultConObject);
    
    const AbstractClassRep::FieldList &list = getFieldList();
 
@@ -328,6 +336,11 @@ void SimObject::writeFields(Stream &stream, U32 tabStop)
          if (!writeField(f->pFieldname, valCopy))
             continue;
 
+         //If the field hasn't been changed from the default value, then don't bother writing it out
+         const char* defaultValueCheck = defaultObject->getDataField(f->pFieldname, array);
+         if (defaultValueCheck != '\0' && dStricmp(defaultValueCheck, valCopy) == 0)
+            continue;
+
          val = valCopy;
 
          U32 expandedBufferSize = ( nBufferSize  * 2 ) + dStrlen(f->pFieldname) + 32;
@@ -362,6 +375,9 @@ void SimObject::writeFields(Stream &stream, U32 tabStop)
    
    if(mFieldDictionary && mCanSaveFieldDictionary)
       mFieldDictionary->writeFields(this, stream, tabStop);
+
+   // Cleanup our created default object
+   delete defaultConObject;
 }
 
 //-----------------------------------------------------------------------------
@@ -1133,7 +1149,7 @@ const char *SimObject::getPrefixedDataField(StringTableEntry fieldName, const ch
 
 //-----------------------------------------------------------------------------
 
-void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *array, const char *value)
+void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *_array, const char *value)
 {
    // Sanity!
    AssertFatal(fieldName != NULL, "Cannot set object field value with NULL field name.");
@@ -1142,7 +1158,7 @@ void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *arr
    // Set value without prefix if there's no value.
    if (*value == 0)
    {
-      setDataField(fieldName, NULL, value);
+      setDataField(fieldName, _array, value);
       return;
    }
 
@@ -1156,7 +1172,7 @@ void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *arr
    if (fieldPrefix == StringTable->EmptyString())
    {
       // No, so set the data field in the usual way.
-      setDataField(fieldName, NULL, value);
+      setDataField(fieldName, _array, value);
       return;
    }
 
@@ -1167,23 +1183,23 @@ void SimObject::setPrefixedDataField(StringTableEntry fieldName, const char *arr
    if (dStrnicmp(value, fieldPrefix, fieldPrefixLength) != 0)
    {
       // No, so set the data field in the usual way.
-      setDataField(fieldName, NULL, value);
+      setDataField(fieldName, _array, value);
       return;
    }
 
    // Yes, so set the data excluding the prefix.
-   setDataField(fieldName, NULL, value + fieldPrefixLength);
+   setDataField(fieldName, _array, value + fieldPrefixLength);
 }
 
 //-----------------------------------------------------------------------------
 
-const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *array, const S32 fieldType)
+const char *SimObject::getPrefixedDynamicDataField(StringTableEntry fieldName, const char *_array, const S32 fieldType)
 {
    // Sanity!
    AssertFatal(fieldName != NULL, "Cannot get field value with NULL field name.");
 
    // Fetch field value.
-   const char* pFieldValue = getDataField(fieldName, array);
+   const char* pFieldValue = getDataField(fieldName, _array);
 
    // Sanity.
    AssertFatal(pFieldValue != NULL, "Field value cannot be NULL.");
@@ -2235,10 +2251,10 @@ bool SimObject::setProtectedName(void *obj, const char *index, const char *data)
 {   
    if (preventNameChanging)
       return false;
-   SimObject *object = static_cast<SimObject*>(obj);
-   
-   if ( object->isProperlyAdded() )
-      object->assignName( data );   
+   SimObject* object = static_cast<SimObject*>(obj);
+
+   if (object->isProperlyAdded())
+      object->assignName(data);
 
    // always return false because we assign the name here
    return false;
@@ -2246,6 +2262,31 @@ bool SimObject::setProtectedName(void *obj, const char *index, const char *data)
 
 //-----------------------------------------------------------------------------
 
+bool SimObject::setInheritFrom(void* obj, const char* index, const char* data)
+{
+   SimObject* object = static_cast<SimObject*>(obj);
+
+   SimObject* parent;
+   if (Sim::findObject(data, parent))
+   {
+      object->setCopySource(parent);
+      object->assignFieldsFrom(parent);
+
+      // copy any substitution statements
+      SimDataBlock* parent_db = dynamic_cast<SimDataBlock*>(parent);
+      if (parent_db)
+      {
+         SimDataBlock* currentNewObject_db = dynamic_cast<SimDataBlock*>(object);
+         if (currentNewObject_db)
+            currentNewObject_db->copySubstitutionsFrom(parent_db);
+      }
+   }
+
+   return true;
+}
+
+//-----------------------------------------------------------------------------
+
 void SimObject::inspectPreApply()
 {
 }

+ 5 - 0
Engine/source/console/simObject.h

@@ -299,6 +299,8 @@ class SimObject: public ConsoleObject, public TamlCallbacks
       SimObject*       nextManagerNameObject;
       SimObject*       nextIdObject;
 
+      StringTableEntry mInheritFrom;
+
       /// SimGroup we're contained in, if any.
       SimGroup*   mGroup;
       
@@ -380,6 +382,9 @@ class SimObject: public ConsoleObject, public TamlCallbacks
       // Object name protected set method
       static bool setProtectedName(void *object, const char *index, const char *data);
 
+      // Sets object to inherit default values from
+      static bool setInheritFrom(void* object, const char* index, const char* data);
+
    public:
       inline void setProgenitorFile(const char* pFile) { mProgenitorFile = StringTable->insert(pFile); }
       inline StringTableEntry getProgenitorFile(void) const { return mProgenitorFile; }

+ 2 - 1
Engine/source/materials/materialDefinition.cpp

@@ -516,7 +516,8 @@ bool Material::writeField(StringTableEntry fieldname, const char* value)
       fieldname == StringTable->insert("overlayTex") ||
       fieldname == StringTable->insert("bumpTex") ||
       fieldname == StringTable->insert("envTex") ||
-      fieldname == StringTable->insert("colorMultiply"))
+      fieldname == StringTable->insert("colorMultiply") ||
+      fieldname == StringTable->insert("internalName"))
       return false;
 
    return Parent::writeField(fieldname, value);

+ 30 - 8
Engine/source/persistence/taml/taml.cpp

@@ -217,11 +217,6 @@ ImplementEnumType(_TamlFormatMode,
 
       FileStream stream;
 
-      if (StringTable->insert("c://.asset.taml") == StringTable->insert(mFilePathBuffer))
-      {
-         bool asdfasdf = true;
-      }
-
       // File opened?
       if (!stream.open(mFilePathBuffer, Torque::FS::File::Write))
       {
@@ -643,6 +638,19 @@ ImplementEnumType(_TamlFormatMode,
       // Fetch field count.
       const U32 fieldCount = fieldList.size();
 
+      ConsoleObject* defaultConObject;
+      SimObject* defaultObject;
+      if (!getWriteDefaults())
+      {
+         // Create a default object of the same type
+         defaultConObject = ConsoleObject::create(pSimObject->getClassName());
+         defaultObject = dynamic_cast<SimObject*>(defaultConObject);
+      
+         // ***Really*** shouldn't happen
+         if (!defaultObject)
+            return;
+      }
+
       // Iterate fields.
       U8 arrayDepth = 0;
       TamlCustomNode* currentArrayNode = NULL;
@@ -709,9 +717,6 @@ ImplementEnumType(_TamlFormatMode,
             if (!pFieldValue)
                pFieldValue = StringTable->EmptyString();
 
-            if (pField->type == TypeBool)
-               pFieldValue = dAtob(pFieldValue) ? "true" : "false";
-
             U32 nBufferSize = dStrlen(pFieldValue) + 1;
             FrameTemp<char> valueCopy(nBufferSize);
             dStrcpy((char *)valueCopy, pFieldValue, nBufferSize);
@@ -720,9 +725,20 @@ ImplementEnumType(_TamlFormatMode,
             if (!pSimObject->writeField(fieldName, valueCopy))
                continue;
 
+            if (!getWriteDefaults())
+            {
+               //If the field hasn't been changed from the default value, then don't bother writing it out
+               const char* fieldData = defaultObject->getDataField(fieldName, indexBuffer);
+               if (fieldData != '\0' && dStricmp(fieldData, pFieldValue) == 0)
+                  continue;
+            }
+
             // Reassign field value.
             pFieldValue = valueCopy;
 
+            if (pField->type == TypeBool)
+               pFieldValue = dAtob(pFieldValue) ? "true" : "false";
+
             // Detect and collapse relative path information
             char fnBuf[1024];
             if ((S32)pField->type == TypeFilename)
@@ -741,6 +757,12 @@ ImplementEnumType(_TamlFormatMode,
             }
          }
       }
+
+      if (!getWriteDefaults())
+      {
+         // Cleanup our created default object
+         delete defaultConObject;
+      }
    }
 
    //-----------------------------------------------------------------------------

+ 16 - 2
Engine/source/persistence/taml/xml/tamlXmlReader.cpp

@@ -293,8 +293,22 @@ void TamlXmlReader::parseAttributes( tinyxml2::XMLElement* pXmlElement, SimObjec
                 attributeName == tamlNamedObjectName )
             continue;
 
-        // Set the field.
-        pSimObject->setPrefixedDataField(attributeName, NULL, pAttribute->Value());
+        //See if we have any sort of array index
+        S32 suffixNum;
+        String trimmedName = String::GetTrailingNumber(attributeName, suffixNum);
+        if (!trimmedName.equal(attributeName))
+        {
+           char arrayIndexStr[32];
+           dItoa(suffixNum, arrayIndexStr);
+
+           // Set the field.
+           pSimObject->setPrefixedDataField(StringTable->insert(trimmedName.c_str()), arrayIndexStr, pAttribute->Value());
+        }
+        else
+        {
+           // Set the field.
+           pSimObject->setPrefixedDataField(attributeName, NULL, pAttribute->Value());
+        }
     }
 }
 

+ 2 - 1
Templates/BaseGame/game/tools/assetBrowser/assetImportConfigs.xml

@@ -47,7 +47,7 @@
             <Setting name="AlwaysAddMaterialSuffix">0</Setting>
             <Setting name="CreateComposites">1</Setting>
             <Setting name="CreateORMConfig">1</Setting>
-            <Setting name="IgnoreMaterials">DefaultMaterial</Setting>
+            <Setting name="IgnoreMaterials">DefaultMaterial,ColorEffect*</Setting>
             <Setting name="ImportMaterials">1</Setting>
             <Setting name="PopulateMaterialMaps">1</Setting>
             <Setting name="UseDiffuseSuffixOnOriginImage">1</Setting>
@@ -130,6 +130,7 @@
             <Setting name="AlwaysAddMaterialSuffix">1</Setting>
             <Setting name="CreateComposites">1</Setting>
             <Setting name="ImportMaterials">1</Setting>
+            <Setting name="IgnoreMaterials">DefaultMaterial,ColorEffect*</Setting>
             <Setting name="PopulateMaterialMaps">1</Setting>
             <Setting name="UseDiffuseSuffixOnOriginImage">1</Setting>
             <Setting name="UseExistingMaterials">1</Setting>

+ 0 - 1
Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript

@@ -2444,7 +2444,6 @@ function AssetBrowserFilterTree::onControlDropped( %this, %payload, %position )
 
 function AssetBrowserFilterTree::onDragDropped( %this )
 {
-   %asdgadfhg =true;
 }
 
 function AssetBrowser::hasLooseFilesInDir(%this)

+ 4 - 4
Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript

@@ -8,7 +8,6 @@ function AssetBrowser::createMaterialAsset(%this)
    %assetPath = AssetBrowser.dirHandler.currentAddress @ "/";   
    
    %tamlpath = %assetPath @ %assetName @ ".asset.taml";
-   %scriptPath = %assetPath @ %assetName @ "." @ $TorqueScriptFileExtension;
    
    %asset = new MaterialAsset()
    {
@@ -16,13 +15,13 @@ function AssetBrowser::createMaterialAsset(%this)
       versionId = 1;
       materialDefinitionName = %assetName;
       scriptFile = %assetName @ "." @ $TorqueScriptFileExtension;
+      
+      new Material(%assetName) {
+      };
    };
    
    TamlWrite(%asset, %tamlpath);
    
-   %mat = new Material(%assetName);
-   %mat.save(%scriptPath);
-   
    %moduleDef = ModuleDatabase.findModule(%moduleName, 1);
 	AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath);
 
@@ -42,6 +41,7 @@ function AssetBrowser::editMaterialAsset(%this, %assetDef)
    
    EditorGui.setEditor(MaterialEditorPlugin);
    
+   MaterialEditorGui.currentMaterialAsset = %assetDef.getAssetId();
    MaterialEditorGui.currentMaterial = %assetDef.materialDefinitionName;
    MaterialEditorGui.setActiveMaterial( %assetDef.materialDefinitionName );
    

+ 28 - 30
Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript

@@ -15,10 +15,37 @@ function AssetBrowser::createTerrainMaterialAsset(%this)
    {
       AssetName = %assetName;
       versionId = 1;
-      scriptFile = %assetName @ "." @ $TorqueScriptFileExtension;
       materialDefinitionName = %assetName;
    };
    
+   %matDef = new TerrainMaterial(%assetName)
+   {
+      internalName = %moduleName @ ":" @ %assetName;
+      diffuseMap = "";
+      detailMap = "";
+      detailSize = "10";
+      isManaged = "1";
+      detailBrightness = "1";
+      Enabled = "1";
+      diffuseSize = "200";
+   };
+   
+   %fxMatDef = new Material("TerrainFX_" @ %assetName)
+   {
+      mapTo = %assetName;
+      footstepSoundId = 0;
+      terrainMaterials = "1";
+      ShowDust = "1";
+      showFootprints = "1";
+      materialTag0 = "Terrain";
+      effectColor[0] = "0.42 0.42 0 1";
+      effectColor[1] = "0.42 0.42 0 1";
+      impactSoundId = "0";
+   };
+   
+   %asset.add(%matDef);
+   %asset.add(%fxMatDef);
+   
    TamlWrite(%asset, %tamlpath);
    
    %moduleDef = ModuleDatabase.findModule(%moduleName, 1);
@@ -28,35 +55,6 @@ function AssetBrowser::createTerrainMaterialAsset(%this)
 
 	AssetBrowser.refresh();
 	
-	//AssetBrowserFilterTree.onSelect(%smItem);
-	
-	%file = new FileObject();
-	%templateFile = new FileObject();
-	
-	%templateFilePath = %this.templateFilesPath @ "terrainMaterial." @ $TorqueScriptFileExtension @ ".template";
-   
-   if(%file.openForWrite(%scriptPath) && %templateFile.openForRead(%templateFilePath))
-   {
-      while( !%templateFile.isEOF() )
-      {
-         %line = %templateFile.readline();
-         %line = strreplace( %line, "@", %assetName );
-         
-         %file.writeline(%line);
-         //echo(%line);
-      }
-      
-      %file.close();
-      %templateFile.close();
-   }
-   else
-   {
-      %file.close();
-      %templateFile.close();
-      
-      warnf("CreateNewTerrainMaterialAsset - Something went wrong and we couldn't write thescript file!");
-   }
-   
    //If we've got the terrain mat editor open, go ahead and update it all
    TerrainMaterialDlg.onWake();
    

+ 16 - 2
Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript

@@ -269,6 +269,7 @@ function SubMaterialSelector::onSelect( %this )
       }
       else
       {
+         MaterialEditorGui.currentMaterialAsset = %material;
          %assetDef = AssetDatabase.acquireAsset(%material);
          %material = %assetDef.materialDefinitionName;  
       }
@@ -1906,6 +1907,7 @@ function MaterialEditorGui::saveDialogDontSave( %this, %material )
    
    if(AssetDatabase.isDeclaredAsset(%material))
    {
+      MaterialEditorGui.currentMaterialAsset = %material;
       %material = AssetDatabase.acquireAsset(%material).materialDefinitionName;
    }
    
@@ -1916,6 +1918,7 @@ function MaterialEditorGui::saveDialogSave( %this, %material )
 {
    if(AssetDatabase.isDeclaredAsset(%material))
    {
+      MaterialEditorGui.currentMaterialAsset = %material;
       %material = AssetDatabase.acquireAsset(%material).materialDefinitionName;
    }
       
@@ -1945,8 +1948,18 @@ function MaterialEditorGui::save( %this )
    if( %currentMaterial.isAutoGenerated() ) 
       %currentMaterial.setAutoGenerated( false ); 
      
-   // Save the material using the persistence manager
-   matEd_PersistMan.saveDirty();   
+   if(MaterialEditorGui.currentMaterialAsset !$= "")
+   {
+      MaterialEditorGui.copyMaterials( materialEd_previewMaterial, notDirtyMaterial );
+      
+      %assetDef = AssetDatabase.acquireAsset(MaterialEditorGui.currentMaterialAsset);
+      %assetDef.saveAsset(); //write it out
+   }
+   else
+   {
+      // Save the material using the persistence manager
+      matEd_PersistMan.saveDirty();   
+   }
    
    // Clean up the Material Editor
    MaterialEditorGui.copyMaterials( materialEd_previewMaterial, notDirtyMaterial );
@@ -2211,6 +2224,7 @@ function MaterialEditorGui::changeMaterial(%this, %fromMaterial, %toMaterial)
    if(AssetDatabase.isDeclaredAsset(%toMaterial))
    {
       %isMatAsset = true;
+      MaterialEditorGui.currentMaterialAsset = %toMaterial;
       %assetDef = AssetDatabase.acquireAsset(%toMaterial);
       %toMaterialDefinition = %assetDef.materialDefinitionName;
       %filename = %assetDef.getScriptPath();

+ 253 - 46
Templates/BaseGame/game/tools/projectImporter/importers/pre40/T3Dpre4ProjectImporter.tscript

@@ -200,7 +200,7 @@ function T3Dpre4ProjectImporter::writeImportingFiles(%this)
       if($ProjectImporter::useExistingModule)
       {
          //clean up legact files if they've been renamed or whatnot
-         if(%file !$= %rootFileSectionObject.fileDestination)
+         if(makeRelativePath(%file) !$= %rootFileSectionObject.fileDestination)
          {
             fileDelete(%file);  
          }
@@ -659,8 +659,6 @@ function T3Dpre4ProjectImporter::processAssetFile(%this, %assetObj)
    if(!isObject(%assetObj))
       return;
       
-   %assetObj.echo();
-      
    //really, we only care here about ensuring the file extensions are cleaned up
    for(%l=0; %l < %assetObj.count(); %l++)
    {
@@ -691,6 +689,9 @@ function T3Dpre4ProjectImporter::beginAssetAndModuleImport(%this)
       
       if(%fileExt $= ".module")
       {
+         if(%rootFileSectionObject.skip)
+            continue;
+            
          projectImporterLog("T3Dpre4ProjectImporter::beginAssetAndModuleImport() - processing file: " @ %file);
          $ProjectImporter::currentFilePath = filePath(%rootFileSectionObject.fileDestination) @ "/";
          %this.processModuleFile(%rootFileSectionObject);
@@ -698,6 +699,9 @@ function T3Dpre4ProjectImporter::beginAssetAndModuleImport(%this)
       }
       else if(%fileExt $= ".asset.taml")
       {
+         if(%rootFileSectionObject.skip)
+            continue;
+            
          projectImporterLog("T3Dpre4ProjectImporter::beginAssetAndModuleImport() - processing file: " @ %file);
          $ProjectImporter::currentFilePath = filePath(%rootFileSectionObject.fileDestination) @ "/";
          %this.processAssetFile(%rootFileSectionObject);
@@ -888,6 +892,77 @@ T3Dpre4ProjectImporter::genProcessor("Material", $MaterialEntriesList);
 //==============================================================================
 function T3Dpre4ProjectImporter::processMaterialObject(%this, %fileObject, %objectName)
 {
+   //first, lets do a bit of use-case checking. Materials are sometimes companion to 
+   //a terrain material for effects and game physics behavior and may not be immediately
+   //obviously assocated. Lets check for that first before processing this as a regular material
+   %mapTo = findObjectField(%fileObject, "mapTo");
+   if(%mapTo !$= "")
+   {
+      %terrainMatAsset = "";
+      %terrainMat = "";
+      if(isObject(%mapTo) && %mapTo.getClassName() $= "TerrainMaterial")
+      {
+         //If the terrain material already exists as a full object, look up it's
+         //asset to associate this FX material to it
+         %terrainMatAsset = TerrainMaterialAsset::getAssetIdByMaterialName(%mapTo.getName());
+         
+         //Now we make our scripted definition "real", and append it to our asset
+         //so it is serialized.
+         %objectDefinition = "";
+         for(%l=0; %l < %fileObject.count(); %l++)
+         {
+            %objectLine = %fileObject.getKey(%l);  
+            if(!isObject(%objectLine))
+            {
+               %objectDefinition = %objectDefinition @ %objectLine;
+            }
+         }
+         
+         eval(%objectDefinition);
+         
+         if(isObject(%objectName))
+         {
+            %terrainMatAsset.add(%objectName);
+            
+            %terrainMatAsset.saveAsset();
+            %fileObject.processed = true;
+            %fileObject.skip = true; //don't write the def back out to script, it's not needed now
+         }
+         
+         return false;
+      }
+      else
+      {
+         //No existing object, so probably incoming with the import, so lets go
+         //look for it
+         %terrMatList = getObjectsInFilesByClass("TerrainMaterial");
+         for(%i=0; %i < getFieldCount(%terrMatList); %i++)
+         {
+            %terrainMatObj = getField(%terrMatList, %i);
+            if(%terrainMatObj.objectName $= %mapTo)
+            {
+               %terrainMat = %terrainMatObj;
+            }
+            else
+            {
+               %terrainObjIntName = findObjectField(%terrainMatObj, "internalName");
+               if(%terrainObjIntName $= %mapTo)
+               {
+                  %terrainMat = %terrainMatObj;
+               }
+            }
+            
+            if(%terrainMat !$= "")
+            {
+               //found it, not imported yet, so mark it for later
+               %terrainMat.FXMaterial = %fileObject;
+               
+               return false;
+            }
+         }
+      }
+   }
+   
    %matAsset = MaterialAsset::getAssetIdByMaterialName(%objectName);
    
    if(%matAsset $= "" || %matAsset $= "Core_Rendering:NoMaterial")
@@ -913,12 +988,11 @@ function T3Dpre4ProjectImporter::processMaterialObject(%this, %fileObject, %obje
          versionId = 1;
          shaderData = "";
          materialDefinitionName = %assetName;
-         scriptFile = fileBase(%scriptPath);
       };
       
       //Now we make our scripted definition "real", and append it to our asset
       //so it is serialized.
-      /*%objectDefinition = "";
+      %objectDefinition = "";
       for(%l=0; %l < %fileObject.count(); %l++)
       {
          %objectLine = %fileObject.getKey(%l);  
@@ -932,8 +1006,14 @@ function T3Dpre4ProjectImporter::processMaterialObject(%this, %fileObject, %obje
       
       if(isObject(%objectName))
       {
+         //if we created it successfully, set up inheritance for serialization if needed
+         if(%fileObject.parentName !$= "")
+         {
+            %objectName.setFieldValue("inheritFrom",%fileObject.parentName);
+         }
+               
          %asset.add(%objectName);
-      }*/
+      }
       
       if(!isDirectory(%assetPath))
       {
@@ -943,26 +1023,6 @@ function T3Dpre4ProjectImporter::processMaterialObject(%this, %fileObject, %obje
       %success = false;
       if(TamlWrite(%asset, %tamlpath))
       {
-         //now write the script file
-         if ( $ProjectImporter::fileObject.openForWrite( %scriptPath ) ) 
-         {
-            for(%i=0; %i < %fileObject.count(); %i++)
-            {
-               %objectLine = %fileObject.getKey(%i);
-               if(isObject(%objectLine))
-               {
-                  %defineLine = %fileObject.getKey(0);
-                  $ProjectImporter::fileObject.writeLine(%defineLine);
-               }
-               else
-               {
-                  $ProjectImporter::fileObject.writeLine(%objectLine);
-               }
-            }
-            
-            $ProjectImporter::fileObject.close();
-         }
-         
          %moduleDef = ModuleDatabase.findModule(%moduleName, 1);
                   
          %success = AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath);
@@ -971,6 +1031,43 @@ function T3Dpre4ProjectImporter::processMaterialObject(%this, %fileObject, %obje
       if(!%success)
          return false;
    }
+   else
+   {
+      //process an existing material asset, if needbe
+      %assetDef = AssetDatabase.acquireAsset(%matAsset);
+      
+      %assetScriptPath = %assetDef.getScriptPath();
+      
+      if(isFile(%assetScriptPath) && isObject(%objectName))
+      {
+         //Regular material in a companion file, so we'll want to write it to the
+         //asset def file instead of the loose file
+         %assetDef.scriptFile = ""; //clear the old script path reference
+         %assetDef.add(%objectName); //child the definition to the asset def
+
+         if(%fileObject.parentName !$= "")
+         {
+            %objectName.setFieldValue("inheritFrom",%fileObject.parentName);
+         }
+         
+         if(%assetDef.saveAsset())
+         {
+            %fileObject.processed = true;
+            %fileObject.skip = true; //don't write the def back out to script, it's not needed now
+            
+            %assetFileObj = findFileInImporting(makeFullPath(AssetDatabase.getAssetFilePath(%matAsset)));
+            
+            echo(%assetFileObj.fileDestination);
+            %assetFileObj.processed = true;
+            %assetFileObj.skip = true; //this asset definition has been processed
+                                       //so nothing else need be done
+         }
+         else
+         {
+            projectImporterLog("T3Dpre4ProjectImporter::processMaterialObject() - failed to save out modified material asset for: " @ %matAsset);  
+         }
+      }
+   }
    
    return false;
 }
@@ -1017,9 +1114,98 @@ function T3Dpre4ProjectImporter::processTerrainMaterialObject(%this, %fileObject
          versionId = 1;
          shaderData = "";
          materialDefinitionName = %objectName;
-         scriptFile = fileName(%scriptPath);
       };
       
+      renameObjectName(%fileObject, %objectName);
+      
+      //Now we make our scripted definition "real", and append it to our asset
+      //so it is serialized.
+      %objectDefinition = "";
+      for(%l=0; %l < %fileObject.count(); %l++)
+      {
+         %objectLine = %fileObject.getKey(%l);  
+         if(!isObject(%objectLine))
+         {
+            %objectDefinition = %objectDefinition @ %objectLine;
+         }
+      }
+      
+      eval(%objectDefinition);
+      
+      if(isObject(%objectName))
+      {
+         //if we created it successfully, set up inheritance for serialization if needed
+         if(%fileObject.parentName !$= "")
+         {
+            %objectName.setFieldValue("inheritFrom",%fileObject.parentName);
+         }
+               
+         %asset.add(%objectName);
+      }
+      else
+      {
+         error("T3Dpre4ProjectImporter::processTerrainMaterialObject() - failed to parse terrainmat object: ");
+         echo(%objectDefinition);
+      }
+      
+      if(%fileObject.FXMaterial $= "")
+      {
+         //on the off-chance it exists, try scanning for FX materials associated
+         //to this terrain material
+         %fxMat = findObjectInFiles("TerrainFX_" @ %objectName);
+         if(%fxMat !$= "" && %objectName.classType $= "Material")
+         {
+            %fileObject.FXMaterial = %fxMat;
+         }
+         else
+         {
+            %fxMatList = getObjectsInFilesByClass("Material");
+            for(%i=0; %i < getFieldCount(%fxMatList); %i++)
+            {
+               %fxMatObj = getField(%fxMatList, %i);
+               %fxMatObjMapTo = findObjectField(%fxMatObj, "mapTo");
+               if(%fxMatObjMapTo $= %objectName)
+               {
+                  %fileObject.FXMaterial = %fxMatObj;
+                  break;
+               }
+            }
+         }
+      }
+      
+      if(%fileObject.FXMaterial !$= "")
+      {
+         //Ensure our mapto is up to date for any name sanitize/tweaks
+         setObjectField(%fileObject.FXMaterial, "mapTo", %objectName);
+         
+         //we associated to an FX material, so process that now
+         %objectDefinition = "";
+         for(%l=0; %l < %fileObject.FXMaterial.count(); %l++)
+         {
+            %objectLine = %fileObject.FXMaterial.getKey(%l);  
+            if(!isObject(%objectLine))
+            {
+               %objectDefinition = %objectDefinition @ %objectLine;
+            }
+         }
+         
+         eval(%objectDefinition);
+         
+         if(isObject(%fileObject.FXMaterial.objectName))
+         {
+            //if we created it successfully, set up inheritance for serialization if needed
+            if(%fileObject.FXMaterial.parentName !$= "")
+            {
+               %fileObject.FXMaterial.setFieldValue("inheritFrom",%fileObject.FXMaterial.parentName);
+            }
+                  
+            %asset.add(%fileObject.FXMaterial.objectName);
+         }
+         
+         %fileObject.FXMaterial.processed = true;
+         %fileObject.FXMaterial.skip = true;
+      }  
+      
       %success = false;
       if(TamlWrite(%asset, %tamlpath))
       {
@@ -1031,6 +1217,43 @@ function T3Dpre4ProjectImporter::processTerrainMaterialObject(%this, %fileObject
       if(!%success)
          return false;
    }
+   else
+   {
+      //process an existing material asset, if needbe
+      %assetDef = AssetDatabase.acquireAsset(%matAsset);
+      
+      %assetScriptPath = %assetDef.getScriptPath();
+      
+      if(isFile(%assetScriptPath) && isObject(%objectName))
+      {
+         //Regular material in a companion file, so we'll want to write it to the
+         //asset def file instead of the loose file
+         %assetDef.scriptFile = ""; //clear the old script path reference
+         %assetDef.add(%objectName); //child the definition to the asset def
+
+         if(%fileObject.parentName !$= "")
+         {
+            %objectName.setFieldValue("inheritFrom",%fileObject.parentName);
+         }
+         
+         if(%assetDef.saveAsset())
+         {
+            %fileObject.processed = true;
+            %fileObject.skip = true; //don't write the def back out to script, it's not needed now
+            
+            %assetFileObj = findFileInImporting(makeFullPath(AssetDatabase.getAssetFilePath(%matAsset)));
+            
+            echo(%assetFileObj.fileDestination);
+            %assetFileObj.processed = true;
+            %assetFileObj.skip = true; //this asset definition has been processed
+                                       //so nothing else need be done
+         }
+         else
+         {
+            projectImporterLog("T3Dpre4ProjectImporter::processTerrainMaterialObject() - failed to save out modified material asset for: " @ %matAsset);  
+         }
+      }
+   }
    
    return false;
 }
@@ -1122,25 +1345,12 @@ function T3Dpre4ProjectImporter::processSFXProfileObject(%this, %file, %objectNa
       }
       else
       {
-         %objFileFinder = "";
-         //first check our cache
-         if(isObject($ProjectImporter::SFXDescriptionCache) && 
-            $ProjectImporter::SFXDescriptionCache.getIndexFromKey(%descriptionName) !$= "")
-         {
-            %key = $ProjectImporter::SFXDescriptionCache.getIndexFromKey(%descriptionName);
-            %objFileFinder = $ProjectImporter::SFXDescriptionCache.getValue(%key);
-         }
-         else
-         {
-            %objFileFinder = findObjectInFiles(%descriptionName);
-         }
+         %fileObj = findObjectInFiles(%descriptionName);
          
-         if(%objFileFinder !$= "")
+         if(%fileObj !$= "")
          {
             %valueArray = new ArrayObject();
                
-            %fileObj = getField(%objFileFinder, 0);
-               
             %valueArray.add("sourceGroup" SPC findObjectField(%fileObj, "sourceGroup"));
             %valueArray.add("volume" SPC findObjectField(%fileObj, "volume"));
             %valueArray.add("pitch" SPC findObjectField(%fileObj, "pitch"));
@@ -1157,10 +1367,7 @@ function T3Dpre4ProjectImporter::processSFXProfileObject(%this, %file, %objectNa
             %valueArray.add("rolloffFactor" SPC findObjectField(%fileObj, "rolloffFactor"));
             %valueArray.add("isStreaming" SPC findObjectField(%fileObj, "isStreaming"));
             
-            if(isObject($ProjectImporter::SFXDescriptionCache))
-            {
-               $ProjectImporter::SFXDescriptionCache.add(%descriptionName, %objFileFinder);
-            }
+            %fileObj.skip = true;
             
             for(%v=0; %v < %valueArray.Count(); %v++)
             {

+ 1 - 1
Templates/BaseGame/game/tools/projectImporter/importers/pre40/pre40ImporterGuis.tscript

@@ -37,7 +37,7 @@ function Pre40ImporterPage0::openPage(%this)
          %sanitizedFilename = sanitizeString(%fileBase);
          if(startsWith(%sanitizedFilename, "_"))
          {
-            %sanitizedFilename = substr(%sanitizedFilename, 1, -1);
+            %sanitizedFilename = getSubstr(%sanitizedFilename, 1, -1);
          }
          if(%sanitizedFilename !$= %fileBase)
          {

+ 185 - 14
Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript

@@ -242,7 +242,7 @@ function ProjectImportWizardPage3::openPage(%this)
    %dataFullPath = makeFullPath("data/");
    %coreFullPath = makeFullPath("core/");
    %toolsFullPath = makeFullPath("tools/");
-   if(startsWith(makeFullPath("data/"), $ProjectImporter::sourceContentFolder))
+   if(startsWith($ProjectImporter::sourceContentFolder, makeFullPath("data/")))
    {
       %moduleDef = AssetBrowser.dirHandler.getModuleFromAddress(makeRelativePath($ProjectImporter::sourceContentFolder));
       if(isObject(%moduleDef))
@@ -254,8 +254,8 @@ function ProjectImportWizardPage3::openPage(%this)
          ProjectImportWindow.setStep(4);
       }
    }
-   else if(startsWith(makeFullPath("core/"), $ProjectImporter::sourceContentFolder) ||
-            startsWith(makeFullPath("tools/"), $ProjectImporter::sourceContentFolder))
+   else if(startsWith($ProjectImporter::sourceContentFolder, makeFullPath("core/")) ||
+            startsWith($ProjectImporter::sourceContentFolder, makeFullPath("tools/")))
    {
       ProjectImportWindow.setStep(5);
    }
@@ -476,7 +476,7 @@ function preprocessImportingFiles()
          {
             %line = $ProjectImporter::fileObject.readLine();
             
-            if(strIsMatchExpr("*new*(*)*", %line) && !strIsMatchExpr("*\"*new*(*)*\"*", %line))
+            if(strIsMatchExpr("* new*(*)*", %line))
             {
                %start = strpos(%line, "new ");
                %end = strpos(%line, "(", %start);
@@ -490,9 +490,11 @@ function preprocessImportingFiles()
                
                %objectName = getSubStr(%line, %end+1, %nameEnd-%end-1);
                
+               %parentName = "";
                %inheritanceSplit = strpos(%objectName, ":");
                if(%inheritanceSplit != -1)
                {
+                  %parentName = getSubStr(%objectName, %inheritanceSplit + 1);
                   %objectName = getSubStr(%objectName, 0, %inheritanceSplit);
                }
                
@@ -502,6 +504,7 @@ function preprocessImportingFiles()
                %currentFileSectionObject.elementType = "object";
                %currentFileSectionObject.classType = %className;
                %currentFileSectionObject.objectName = %objectName;
+               %currentFileSectionObject.parentName = %parentName;
                %currentFileSectionObject.fileName = %file;
                %currentFileSectionObject.skip = false;
                %currentFileSectionObject.fileDestination = %rootFileSectionObject.fileDestination;
@@ -510,6 +513,7 @@ function preprocessImportingFiles()
                %currentFileSectionObject.add(%line);
 
                %parentFileSectionObject.add(%currentFileSectionObject);
+               %currentFileSectionObject.parentElement = %parentFileSectionObject;
                
                //Now for a sanity check, see if we kill the object on the same line as we make it
                //sometimes people try and be 'efficient' with their code linecount wise
@@ -526,7 +530,7 @@ function preprocessImportingFiles()
                      %insideObjectBlock = true;
                }
             }
-            else if(strIsMatchExpr("*datablock*(*)*", %line))
+            else if(strIsMatchExpr("* datablock*(*)*", %line))
             {
                %start = strpos(%line, "datablock ");
                %end = strpos(%line, "(", %start);
@@ -540,9 +544,11 @@ function preprocessImportingFiles()
                
                %objectName = getSubStr(%line, %end+1, %nameEnd-%end-1);
                
+               %parentName = "";
                %inheritanceSplit = strpos(%objectName, ":");
                if(%inheritanceSplit != -1)
                {
+                  %parentName = getSubStr(%objectName, %inheritanceSplit + 1);
                   %objectName = getSubStr(%objectName, 0, %inheritanceSplit);
                }
                
@@ -552,6 +558,7 @@ function preprocessImportingFiles()
                %currentFileSectionObject.elementType = "object";
                %currentFileSectionObject.classType = %className;
                %currentFileSectionObject.objectName = %objectName;
+               %currentFileSectionObject.parentName = %parentName;
                %currentFileSectionObject.fileName = %file;
                %currentFileSectionObject.skip = false;
                %currentFileSectionObject.fileDestination = %rootFileSectionObject.fileDestination;
@@ -560,6 +567,7 @@ function preprocessImportingFiles()
                %currentFileSectionObject.add(%line);
 
                %parentFileSectionObject.add(%currentFileSectionObject);
+               %currentFileSectionObject.parentElement = %parentFileSectionObject;
                
                //Now for a sanity check, see if we kill the object on the same line as we make it
                //sometimes people try and be 'efficient' with their code linecount wise
@@ -576,7 +584,7 @@ function preprocessImportingFiles()
                      %insideObjectBlock = true;
                }
             }
-            else if(strIsMatchExpr("*singleton*(*)*", %line))
+            else if(strIsMatchExpr("* singleton*(*)*", %line))
             {
                %start = strpos(%line, "singleton ");
                %end = strpos(%line, "(", %start);
@@ -590,9 +598,11 @@ function preprocessImportingFiles()
                
                %objectName = getSubStr(%line, %end+1, %nameEnd-%end-1);
                
+               %parentName = "";
                %inheritanceSplit = strpos(%objectName, ":");
                if(%inheritanceSplit != -1)
                {
+                  %parentName = getSubStr(%objectName, %inheritanceSplit + 1);
                   %objectName = getSubStr(%objectName, 0, %inheritanceSplit);
                }
 
@@ -602,6 +612,7 @@ function preprocessImportingFiles()
                %currentFileSectionObject.elementType = "object";
                %currentFileSectionObject.classType = %className;
                %currentFileSectionObject.objectName = %objectName;
+               %currentFileSectionObject.parentName = %parentName;
                %currentFileSectionObject.fileName = %file;
                %currentFileSectionObject.skip = false;
                %currentFileSectionObject.fileDestination = %rootFileSectionObject.fileDestination;
@@ -610,6 +621,7 @@ function preprocessImportingFiles()
                %currentFileSectionObject.add(%line);
 
                %parentFileSectionObject.add(%currentFileSectionObject);
+               %currentFileSectionObject.parentElement = %parentFileSectionObject;
                
                //Now for a sanity check, see if we kill the object on the same line as we make it
                //sometimes people try and be 'efficient' with their code linecount wise
@@ -650,6 +662,7 @@ function preprocessImportingFiles()
                %currentFileSectionObject.add(%line);
                
                %parentFileSectionObject.add(%currentFileSectionObject);
+               %currentFileSectionObject.parentElement = %parentFileSectionObject;
                
                if(strIsMatchExpr("*{*", %line))
                {
@@ -838,6 +851,104 @@ function isImportingFile(%checkFile)
    return false;
 }
 
+//==============================================================================
+// Returns the file object of the file in question is part of our pre-scanned list of importing files
+//==============================================================================
+function findFileInImporting(%checkFile)
+{
+   for(%i=0; %i < $ProjectImporter::FileList.count(); %i++)
+   {
+      %file = $ProjectImporter::FileList.getKey(%i);
+      
+      if(%file $= %checkFile)
+         return $ProjectImporter::FileList.getValue(%i);
+   }
+   
+   return "";
+}
+
+//==============================================================================
+// Checks if the object in question is defined in any of our pre-scanned list of importing files
+//==============================================================================
+function findObjectInFilesRecurse(%objectName, %arrayObj)
+{
+   for(%i=0; %i < %arrayObj.count(); %i++)
+   {
+      %objectLine = %arrayObj.getKey(%i);
+      if(isObject(%objectLine))
+      {
+         if(%objectLine.objectName $= %objectName)
+            return %objectLine;
+            
+         //If this object isn't it, try recursing any children
+         %result = findObjectInFilesRecurse(%objectName, %objectLine);
+         if(%result !$= "")
+            return %result;
+      }
+   }
+   
+   return "";
+}
+
+function findObjectInFiles(%objectName)
+{
+   for(%i=0; %i < $ProjectImporter::FileList.count(); %i++)
+   {
+      %objectLine = $ProjectImporter::FileList.getValue(%i);
+      if(isObject(%objectLine))
+      {
+         if(%objectLine.objectName $= %objectName)
+            return %objectLine;
+            
+         //If this object isn't it, try recursing any children
+         %result = findObjectInFilesRecurse(%objectName, %objectLine);
+         if(%result !$= "")
+            return %result;
+      }
+   }
+   
+   return "";
+}
+
+//==============================================================================
+// Checks if the object in question is defined in any of our pre-scanned list of importing files
+//==============================================================================
+function getObjectsInFilesByClassRecurse(%className, %arrayObj)
+{
+   for(%i=0; %i < %arrayObj.count(); %i++)
+   {
+      %objectLine = %arrayObj.getKey(%i);
+      if(isObject(%objectLine))
+      {
+         if(%objectLine.classType $= %className)
+            $ProjectImporter::queryList = $ProjectImporter::queryList TAB %objectLine;
+            
+         //If this object isn't it, try recursing any children
+         getObjectsInFilesByClassRecurse(%className, %objectLine);
+      }
+   }
+}
+
+function getObjectsInFilesByClass(%className)
+{
+   $ProjectImporter::queryList = "";
+      
+   for(%i=0; %i < $ProjectImporter::FileList.count(); %i++)
+   {
+      %objectLine = $ProjectImporter::FileList.getValue(%i);
+      if(isObject(%objectLine))
+      {
+         if(%objectLine.classType $= %className)
+            $ProjectImporter::queryList = $ProjectImporter::queryList TAB %objectLine;
+            
+         //If this object isn't it, try recursing any children
+         getObjectsInFilesByClassRecurse(%className, %objectLine);
+      }
+   }
+   
+   return ltrim($ProjectImporter::queryList);
+}
+
 //==============================================================================
 // Takes a filename lacking an extension and then checks common file extensions
 // to see if we can find the actual file in question
@@ -1055,18 +1166,30 @@ function renameObjectName(%object, %newName)
       %objectLine = %object.getKey(%e);
       if(!isObject(%objectLine))
       {
-         if(strIsMatchExpr("*singleton*(*)*", %objectLine) && 
-            strIsMatchExpr("*new*(*)*", %objectLine) && 
+         if(strIsMatchExpr("*singleton*(*)*", %objectLine) || 
+            strIsMatchExpr("*new*(*)*", %objectLine) || 
             strIsMatchExpr("*datablock*(*)*", %objectLine))
          {
-            %newLine = strreplace(%object.objectName, %newName);
-            
-            echo("renameObjectName() - lines changed from:");
-            echo(%objectLine);
-            echo("to:");
-            echo(%newLine);
+            if(%object.objectName $= "")
+            {
+               %start = strpos(%objectLine, "(");
+               %end = strpos(%objectLine, ")", %start);
+               
+               %preString = getSubStr(%objectLine, 0, %start+1);
+               %postString = getSubStr(%objectLine, %end);
+               
+               %renamedString = %preString @ %newName @ %postString;
+               
+               %newLine = %renamedString;
+            }
+            else
+            {
+               %newLine = strreplace(%objectLine, %object.objectName, %newName);
+            }
             
             %object.setKey(%newLine, %e);
+            
+            %object.objectName = %newName;
          }  
       }
    }
@@ -1203,6 +1326,28 @@ function setObjectField(%object, %fieldName, %newValue)
    }
 }
 
+//==============================================================================
+// Inserts a new field to an object's block in the preprocessed data
+//==============================================================================
+function insertObjectLine(%object, %newLine)
+{
+   for(%e=0; %e < %object.count(); %e++)
+   {
+      %objectLine = %object.getKey(%e);
+      
+      if(strIsMatchExpr("*{*", %objectLine) || 
+            strIsMatchExpr("*singleton*(*)*", %objectLine) || 
+            strIsMatchExpr("*new*(*)*", %objectLine) || 
+            strIsMatchExpr("*datablock*(*)*", %objectLine))
+      {
+         continue;
+      }
+      
+      %object.insert(%newLine, "", %e);
+      return;
+   }
+}
+
 //==============================================================================
 // Takes a string and adds it to the importer's log. Optionally can print the line
 // directly to console for debugging purposes
@@ -1215,6 +1360,32 @@ function projectImporterLog(%line)
    $ProjectImporter::log.add(%line);
 }
 
+//==============================================================================
+// Traverses the object delcaration stack backwards to find the root file object
+//==============================================================================
+function getParentFileObjectFromObject(%object)
+{
+   while(%object.parentElement !$= "")
+   {
+      %object = %object.parentElement;
+   }
+   
+   return %object;
+}
+
+//==============================================================================
+// Traverses the object delcaration stack backwards to find the root file object
+//==============================================================================
+function getParentFileObjectFromObject(%object)
+{
+   while(%object.parentElement !$= "")
+   {
+      %object = %object.parentElement;
+   }
+   
+   return %object;
+}
+
 //==============================================================================
 //Shape Importing
 //==============================================================================

+ 3 - 21
Templates/BaseGame/game/tools/worldEditor/scripts/interfaces/terrainMaterialDlg.ed.tscript

@@ -77,9 +77,6 @@ function TerrainMaterialDlg::showByObjectId( %this, %matObjectId, %onApplyCallba
 
 function TerrainMaterialDlg::onWake( %this )
 {
-   if( !isObject( ETerrainMaterialPersistMan ) )
-      new PersistenceManager( ETerrainMaterialPersistMan );
-      
    if( !isObject( TerrainMaterialDlgNewGroup ) )
       new SimGroup( TerrainMaterialDlgNewGroup );
    if( !isObject( TerrainMaterialDlgDeleteGroup ) )
@@ -156,9 +153,6 @@ function TerrainMaterialDlg::dialogApply( %this )
    // Make sure we save any changes to the current selection.
    %this.saveDirtyMaterial( %this.activeMat );
    
-   // Save all changes.
-   ETerrainMaterialPersistMan.saveDirty();
-   
    // Delete the snapshot.
    TerrainMaterialDlgSnapshot.delete();
 
@@ -191,10 +185,6 @@ function TerrainMaterialDlg::closeDialog( %this )
    
    %this.restoreMaterials();
    
-   // Clear the persistence manager state.
-   
-   ETerrainMaterialPersistMan.clearAll();
-   
    // Delete all new object we have created.
    
    TerrainMaterialDlgNewGroup.clear();
@@ -599,17 +589,9 @@ function TerrainMaterialDlg::saveDirtyMaterial( %this, %mat )
    %mat.isSRGB = %isSRGB;
    %mat.invertRoughness = %invertRoughness;
    
-   // Mark the material as dirty and needing saving.
-   
-   %fileName = %mat.getFileName();
-   if( %fileName $= "" )
-   {
-      error("TerrainMaterialDlg::saveDirtyMaterial() - terrain material doesn't have a fileName set to save to.");
-      return;
-      //%fileName = "data/terrains/materials." @ $TorqueScriptFileExtension;
-   }
-      
-   ETerrainMaterialPersistMan.setDirty( %mat, %fileName ); 
+   //Save the material asset
+   %assetDef = AssetDatabase.acquireAsset(%mat.internalName);
+   %assetDef.saveAsset();
 }
 
 //-----------------------------------------------------------------------------