Browse Source

* Update levelAsset creation so it can be flagged to be creating a subScene preemptively, improving workflow when creating a SubScene level asset 'in place' via the inspector.
* Fixed issue of creating new SubScene using the full level template instead of a blank level file
* Fixed subScene inspector field handling so clicking the create new will mark the 'in place' created level asset as a subscene appropriately
* Changed up persistenceManager logic when parsing objects out - especially with specialty fields - to use Strings instead of const char* to simplify memory juggling and improve stability
* Rolled back specialty array field outputs for decal roads and convex shapes to have the field names in the output again
* Added sanity check for MeshRoad's when writing out via specialty array field to ensure there are profile nodes before trying to write any
* Added sanity check to avoid pointlessly writing out meshroad and river position field into subScene file as it could cause a transform double-up and cause them to move when loading from a subscene

JeffR 8 months ago
parent
commit
0d338f2d51

+ 26 - 1
Engine/source/T3D/SubScene.cpp

@@ -3,6 +3,8 @@
 #include "gameMode.h"
 #include "gameMode.h"
 #include "console/persistenceManager.h"
 #include "console/persistenceManager.h"
 #include "console/script.h"
 #include "console/script.h"
+#include "environment/meshRoad.h"
+#include "environment/river.h"
 #include "scene/sceneRenderState.h"
 #include "scene/sceneRenderState.h"
 #include "renderInstance/renderPassManager.h"
 #include "renderInstance/renderPassManager.h"
 #include "gfx/gfxDrawUtil.h"
 #include "gfx/gfxDrawUtil.h"
@@ -29,7 +31,8 @@ SubScene::SubScene() :
    mFreezeLoading(false),
    mFreezeLoading(false),
    mTickPeriodMS(1000),
    mTickPeriodMS(1000),
    mCurrTick(0),
    mCurrTick(0),
-   mGlobalLayer(false)
+   mGlobalLayer(false),
+   mSaving(false)
 {
 {
    mNetFlags.set(Ghostable | ScopeAlways);
    mNetFlags.set(Ghostable | ScopeAlways);
 
 
@@ -65,6 +68,7 @@ void SubScene::initPersistFields()
    addGroup("SubScene");
    addGroup("SubScene");
    addField("isGlobalLayer", TypeBool, Offset(mGlobalLayer, SubScene), "");
    addField("isGlobalLayer", TypeBool, Offset(mGlobalLayer, SubScene), "");
    INITPERSISTFIELD_LEVELASSET(Level, SubScene, "The level asset to load.");
    INITPERSISTFIELD_LEVELASSET(Level, SubScene, "The level asset to load.");
+   addField("tickPeriodMS", TypeS32, Offset(mTickPeriodMS, SubScene), "evaluation rate (ms)");
    addField("gameModes", TypeGameModeList, Offset(mGameModesNames, SubScene), "The game modes that this subscene is associated with.");
    addField("gameModes", TypeGameModeList, Offset(mGameModesNames, SubScene), "The game modes that this subscene is associated with.");
    endGroup("SubScene");
    endGroup("SubScene");
 
 
@@ -263,6 +267,9 @@ void SubScene::_onFileChanged(const Torque::Path& path)
    if(mLevelAsset.isNull() || Torque::Path(mLevelAsset->getLevelPath()) != path)
    if(mLevelAsset.isNull() || Torque::Path(mLevelAsset->getLevelPath()) != path)
       return;
       return;
 
 
+   if (mSaving)
+      return;
+
    AssertFatal(path == mLevelAsset->getLevelPath(), "Prefab::_onFileChanged - path does not match filename.");
    AssertFatal(path == mLevelAsset->getLevelPath(), "Prefab::_onFileChanged - path does not match filename.");
 
 
    _closeFile(false);
    _closeFile(false);
@@ -336,6 +343,9 @@ void SubScene::load()
    if (mFreezeLoading)
    if (mFreezeLoading)
       return;
       return;
 
 
+   if (mSaving)
+      return;
+
    _loadFile(true);
    _loadFile(true);
    mLoaded = true;
    mLoaded = true;
 
 
@@ -362,6 +372,9 @@ void SubScene::unload()
    if (mFreezeLoading)
    if (mFreezeLoading)
       return;
       return;
 
 
+   if (mSaving)
+      return;
+
    if (isSelected())
    if (isSelected())
    {
    {
       mStartUnloadTimerMS = Sim::getCurrentTime();
       mStartUnloadTimerMS = Sim::getCurrentTime();
@@ -421,10 +434,15 @@ bool SubScene::save()
    if (mLevelAsset.isNull())
    if (mLevelAsset.isNull())
       return false;
       return false;
 
 
+   if (mSaving)
+      return false;
+
    //If we're flagged for unload, push back the unload timer so we can't accidentally trip be saving partway through an unload
    //If we're flagged for unload, push back the unload timer so we can't accidentally trip be saving partway through an unload
    if (mStartUnloadTimerMS != -1)
    if (mStartUnloadTimerMS != -1)
       mStartUnloadTimerMS = Sim::getCurrentTime();
       mStartUnloadTimerMS = Sim::getCurrentTime();
 
 
+   mSaving = true;
+
    PersistenceManager prMger;
    PersistenceManager prMger;
 
 
    StringTableEntry levelPath = mLevelAsset->getLevelPath();
    StringTableEntry levelPath = mLevelAsset->getLevelPath();
@@ -449,6 +467,11 @@ bool SubScene::save()
             prMger.setDirty((*itr), levelPath);
             prMger.setDirty((*itr), levelPath);
          }
          }
       }
       }
+
+      if(dynamic_cast<MeshRoad*>(childObj) || dynamic_cast<River*>(childObj))
+      {
+         prMger.addRemoveField(childObj, "position");
+      }
    }
    }
 
 
    prMger.saveDirty();
    prMger.saveDirty();
@@ -466,6 +489,8 @@ bool SubScene::save()
    //Finally, save
    //Finally, save
    saveSuccess = mLevelAsset->saveAsset();
    saveSuccess = mLevelAsset->saveAsset();
 
 
+   mSaving = false;
+
    return saveSuccess;
    return saveSuccess;
 }
 }
 
 

+ 1 - 0
Engine/source/T3D/SubScene.h

@@ -40,6 +40,7 @@ private:
    S32 mStartUnloadTimerMS;
    S32 mStartUnloadTimerMS;
 
 
    bool mLoaded;
    bool mLoaded;
+   bool mSaving;
    bool mFreezeLoading;
    bool mFreezeLoading;
 
 
    String mLoadIf;
    String mLoadIf;

+ 10 - 2
Engine/source/T3D/assets/LevelAsset.cpp

@@ -43,6 +43,7 @@
 // Debug Profiling.
 // Debug Profiling.
 #include "platform/profiler.h"
 #include "platform/profiler.h"
 #include "gfx/gfxDrawUtil.h"
 #include "gfx/gfxDrawUtil.h"
+#include "T3D/SubScene.h"
 
 
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -479,8 +480,15 @@ GuiControl* GuiInspectorTypeLevelAssetPtr::constructEditControl()
    // Create "Open in Editor" button
    // Create "Open in Editor" button
    mEditButton = new GuiBitmapButtonCtrl();
    mEditButton = new GuiBitmapButtonCtrl();
 
 
-   dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; AssetBrowser.setupCreateNewAsset(\"LevelAsset\", AssetBrowser.selectedModule, \"createAndAssignLevelAsset\");",
-      getIdString());
+   String setSubSceneValue = "$createLevelAssetIsSubScene = \"\";";
+   if(dynamic_cast<SubScene*>(mInspector->getInspectObject()) != NULL)
+   {
+      setSubSceneValue = "$createLevelAssetIsSubScene = true;";
+   }
+
+   dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; %s AssetBrowser.setupCreateNewAsset(\"LevelAsset\", AssetBrowser.selectedModule, \"createAndAssignLevelAsset\");",
+      getIdString(),
+      setSubSceneValue.c_str());
    mEditButton->setField("Command", szBuffer);
    mEditButton->setField("Command", szBuffer);
 
 
    char bitmapName[512] = "ToolsModule:iconAdd_image";
    char bitmapName[512] = "ToolsModule:iconAdd_image";

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

@@ -526,7 +526,7 @@ const char* ConvexShape::getSpecialFieldOut(StringTableEntry fieldName, const U3
       char buffer[1024];
       char buffer[1024];
       dMemset(buffer, 0, 1024);
       dMemset(buffer, 0, 1024);
 
 
-      dSprintf(buffer, 1024, "%g %g %g %g %g %g %g %i %g %g %g %g %g %i %i",
+      dSprintf(buffer, 1024, "surface = \"%g %g %g %g %g %g %g %i %g %g %g %g %g %i %i\";",
          quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z, mSurfaceUVs[index].matID,
          quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z, mSurfaceUVs[index].matID,
          mSurfaceUVs[index].offset.x, mSurfaceUVs[index].offset.y, mSurfaceUVs[index].scale.x,
          mSurfaceUVs[index].offset.x, mSurfaceUVs[index].offset.y, mSurfaceUVs[index].scale.x,
          mSurfaceUVs[index].scale.y, mSurfaceUVs[index].zRot, mSurfaceUVs[index].horzFlip, mSurfaceUVs[index].vertFlip);
          mSurfaceUVs[index].scale.y, mSurfaceUVs[index].zRot, mSurfaceUVs[index].horzFlip, mSurfaceUVs[index].vertFlip);
@@ -541,7 +541,7 @@ const char* ConvexShape::getSpecialFieldOut(StringTableEntry fieldName, const U3
       char buffer[1024];
       char buffer[1024];
       dMemset(buffer, 0, 1024);
       dMemset(buffer, 0, 1024);
 
 
-      dSprintf(buffer, 1024, "%s", mSurfaceTextures[index].getMaterial());
+      dSprintf(buffer, 1024, "surfaceTexture = \"%s\";", mSurfaceTextures[index].getMaterial());
 
 
       return StringTable->insert(buffer);
       return StringTable->insert(buffer);
    }
    }

+ 38 - 71
Engine/source/console/persistenceManager.cpp

@@ -1224,13 +1224,13 @@ void PersistenceManager::removeField(const ParsedProperty& prop)
   removeTextBlock(prop.startLine, prop.endLine, prop.startPosition, endPosition, true);
   removeTextBlock(prop.startLine, prop.endLine, prop.startPosition, endPosition, true);
 }
 }
 
 
-U32 PersistenceManager::writeProperties(const Vector<const char*>& properties, const U32 insertLine, const char* objectIndent)
+U32 PersistenceManager::writeProperties(const Vector<String>& properties, const U32 insertLine, const char* objectIndent)
 {
 {
    U32 currInsertLine = insertLine;
    U32 currInsertLine = insertLine;
 
 
    for (U32 i = 0; i < properties.size(); i++)
    for (U32 i = 0; i < properties.size(); i++)
    {
    {
-      const char* prop = properties[i];
+      const char* prop = properties[i].c_str();
 
 
       if (!prop || dStrlen(prop) == 0)
       if (!prop || dStrlen(prop) == 0)
          continue;
          continue;
@@ -1248,7 +1248,7 @@ U32 PersistenceManager::writeProperties(const Vector<const char*>& properties, c
    return currInsertLine - insertLine;
    return currInsertLine - insertLine;
 }
 }
 
 
-PersistenceManager::ParsedObject* PersistenceManager::writeNewObject(SimObject* object, const Vector<const char*>& properties, const U32 insertLine, ParsedObject* parentObject)
+PersistenceManager::ParsedObject* PersistenceManager::writeNewObject(SimObject* object, const Vector<String>& properties, const U32 insertLine, ParsedObject* parentObject)
 {
 {
    ParsedObject* parsedObject = new ParsedObject;
    ParsedObject* parsedObject = new ParsedObject;
 
 
@@ -1353,7 +1353,7 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
    if (!defaultObject)
    if (!defaultObject)
       return;
       return;
 
 
-   Vector<const char*> newLines;
+   Vector<String> newLines;
 
 
    ParsedObject* parsedObject = findParsedObject(object, parentObject);
    ParsedObject* parsedObject = findParsedObject(object, parentObject);
 
 
@@ -1392,10 +1392,10 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
 
 
          for(U32 j = 0; j < fieldArraySize; j++)
          for(U32 j = 0; j < fieldArraySize; j++)
          {
          {
-            const char* value = object->getSpecialFieldOut(f->pFieldname, j);
+            String value = object->getSpecialFieldOut(f->pFieldname, j);
 
 
             // Make sure we got a value
             // Make sure we got a value
-            if (!value)
+            if (value.isEmpty())
                continue;
                continue;
 
 
             // Let's see if this field is already in the file
             // Let's see if this field is already in the file
@@ -1409,13 +1409,12 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                if (findRemoveField(object, f->pFieldname, j))
                if (findRemoveField(object, f->pFieldname, j))
                {
                {
                   removeField(parsedObject->properties[propertyIndex]);
                   removeField(parsedObject->properties[propertyIndex]);
-                  dFree(value);
                   continue;
                   continue;
                }
                }
 
 
                // Run the parsed value through the console system conditioners so
                // Run the parsed value through the console system conditioners so
                // that it will better match the data we got back from the object.
                // that it will better match the data we got back from the object.
-               const char* evalue = Con::getFormattedData(f->type, prop.value, f->table, f->flag);
+               String evalue = Con::getFormattedData(f->type, prop.value, f->table, f->flag);
 
 
                // If our data doesn't match then we get to update it.
                // If our data doesn't match then we get to update it.
                //
                //
@@ -1423,17 +1422,17 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                // is there in the file, the user does not want it inherited from the copy-source
                // is there in the file, the user does not want it inherited from the copy-source
                // even in the case the actual values are identical.
                // even in the case the actual values are identical.
 
 
-               if (dStricmp(value, evalue) != 0)
+               if (value != evalue)
                {
                {
-                  if (value[0] == '\0' &&
-                     dStricmp(getFieldValue(defaultObject, f->pFieldname, j), value) == 0 &&
-                     (!object->getCopySource() || dStricmp(getFieldValue(object->getCopySource(), f->pFieldname, j), value) == 0))
+                  if (value.isEmpty() &&
+                     dStricmp(getFieldValue(defaultObject, f->pFieldname, j), value.c_str()) == 0 &&
+                     (!object->getCopySource() || dStricmp(getFieldValue(object->getCopySource(), f->pFieldname, j), value.c_str()) == 0))
                   {
                   {
                      removeField(prop);
                      removeField(prop);
                   }
                   }
                   else
                   else
                   {
                   {
-                     updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, value, true);
+                     updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, value.c_str(), true);
                   }
                   }
                }
                }
             }
             }
@@ -1442,7 +1441,6 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                // No need to process a removed field that doesn't exist in the file
                // No need to process a removed field that doesn't exist in the file
                if (findRemoveField(object, f->pFieldname, j))
                if (findRemoveField(object, f->pFieldname, j))
                {
                {
-                  dFree(value);
                   continue;
                   continue;
                }
                }
 
 
@@ -1452,20 +1450,17 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                // then we need to compare against the default value
                // then we need to compare against the default value
                // for this property and save it out if it is different
                // for this property and save it out if it is different
 
 
-               const char* defaultValue = defaultObject->getSpecialFieldOut(f->pFieldname, j);
-               if (!defaultValue || dStricmp(value, defaultValue) != 0)
+               String defaultValue = defaultObject->getSpecialFieldOut(f->pFieldname, j);
+               if (defaultValue.isEmpty() || value != defaultValue)
                {
                {
                   // Value differs.  Check whether it also differs from the
                   // Value differs.  Check whether it also differs from the
                   // value in the copy source if there is one.
                   // value in the copy source if there is one.
 
 
                   if (object->getCopySource())
                   if (object->getCopySource())
                   {
                   {
-                     const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
-                     if (!copySourceValue || dStricmp(copySourceValue, value) != 0)
+                     String copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
+                     if (copySourceValue.isEmpty() || copySourceValue != value)
                         mustUpdate = true;
                         mustUpdate = true;
-
-                     if (copySourceValue)
-                        dFree(copySourceValue);
                   }
                   }
                   else
                   else
                      mustUpdate = true;
                      mustUpdate = true;
@@ -1478,12 +1473,9 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
 
 
                   if (object->getCopySource())
                   if (object->getCopySource())
                   {
                   {
-                     const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
-                     if (copySourceValue && dStricmp(copySourceValue, value) != 0)
+                     String copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
+                     if (!copySourceValue.isEmpty() && copySourceValue != value)
                         mustUpdate = true;
                         mustUpdate = true;
-
-                     if (copySourceValue)
-                        dFree(copySourceValue);
                   }
                   }
                }
                }
 
 
@@ -1498,11 +1490,8 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                // value then add it to the ParsedObject's newLines                        
                // value then add it to the ParsedObject's newLines                        
                if (mustUpdate)
                if (mustUpdate)
                {
                {
-                  newLines.push_back(String(value).c_str());
+                  newLines.push_back(value);
                }
                }
-
-               if (defaultValue)
-                  dFree(defaultValue);
             }
             }
 
 
             //dFree(value);
             //dFree(value);
@@ -1512,10 +1501,10 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
       {
       {
          for (U32 j = 0; S32(j) < f->elementCount; j++)
          for (U32 j = 0; S32(j) < f->elementCount; j++)
          {
          {
-            const char* value = getFieldValue(object, f->pFieldname, j);
+            String value = getFieldValue(object, f->pFieldname, j);
 
 
             // Make sure we got a value
             // Make sure we got a value
-            if (!value)
+            if (value.isEmpty())
                continue;
                continue;
 
 
             // Let's see if this field is already in the file
             // Let's see if this field is already in the file
@@ -1526,16 +1515,15 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                ParsedProperty& prop = parsedObject->properties[propertyIndex];
                ParsedProperty& prop = parsedObject->properties[propertyIndex];
 
 
                // If this field is on the remove list then remove it and continue
                // If this field is on the remove list then remove it and continue
-               if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value))
+               if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value.c_str()))
                {
                {
                   removeField(parsedObject->properties[propertyIndex]);
                   removeField(parsedObject->properties[propertyIndex]);
-                  dFree(value);
                   continue;
                   continue;
                }
                }
 
 
                // Run the parsed value through the console system conditioners so
                // Run the parsed value through the console system conditioners so
                // that it will better match the data we got back from the object.
                // that it will better match the data we got back from the object.
-               const char* evalue = Con::getFormattedData(f->type, prop.value, f->table, f->flag);
+               String evalue = Con::getFormattedData(f->type, prop.value, f->table, f->flag);
 
 
                // If our data doesn't match then we get to update it.
                // If our data doesn't match then we get to update it.
                //
                //
@@ -1543,11 +1531,11 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                // is there in the file, the user does not want it inherited from the copy-source
                // is there in the file, the user does not want it inherited from the copy-source
                // even in the case the actual values are identical.
                // even in the case the actual values are identical.
 
 
-               if (dStricmp(value, evalue) != 0)
+               if (value != evalue)
                {
                {
-                  if (value[0] == '\0' &&
-                     dStricmp(getFieldValue(defaultObject, f->pFieldname, j), value) == 0 &&
-                     (!object->getCopySource() || dStricmp(getFieldValue(object->getCopySource(), f->pFieldname, j), value) == 0))
+                  if (value.isEmpty() &&
+                     dStricmp(getFieldValue(defaultObject, f->pFieldname, j), value.c_str()) == 0 &&
+                     (!object->getCopySource() || dStricmp(getFieldValue(object->getCopySource(), f->pFieldname, j), value.c_str()) == 0))
                   {
                   {
                      removeField(prop);
                      removeField(prop);
                   }
                   }
@@ -1563,14 +1551,14 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                         f->type == TypeSoundFilename)
                         f->type == TypeSoundFilename)
                      {
                      {
                         char fnBuf[1024];
                         char fnBuf[1024];
-                        Con::collapseScriptFilename(fnBuf, 1024, value);
+                        Con::collapseScriptFilename(fnBuf, 1024, value.c_str());
 
 
                         updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, fnBuf, true);
                         updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, fnBuf, true);
                      }
                      }
                      else if (f->type == TypeCommand || f->type == TypeString || f->type == TypeRealString)
                      else if (f->type == TypeCommand || f->type == TypeString || f->type == TypeRealString)
                      {
                      {
                         char cmdBuf[1024];
                         char cmdBuf[1024];
-                        expandEscape(cmdBuf, value);
+                        expandEscape(cmdBuf, value.c_str());
 
 
                         updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, cmdBuf, true);
                         updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, cmdBuf, true);
                      }
                      }
@@ -1582,9 +1570,8 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
             else
             else
             {
             {
                // No need to process a removed field that doesn't exist in the file
                // No need to process a removed field that doesn't exist in the file
-               if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value))
+               if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value.c_str()))
                {
                {
-                  dFree(value);
                   continue;
                   continue;
                }
                }
 
 
@@ -1594,20 +1581,17 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                // then we need to compare against the default value
                // then we need to compare against the default value
                // for this property and save it out if it is different
                // for this property and save it out if it is different
 
 
-               const char* defaultValue = getFieldValue(defaultObject, f->pFieldname, j);
-               if (!defaultValue || dStricmp(value, defaultValue) != 0)
+               String defaultValue = getFieldValue(defaultObject, f->pFieldname, j);
+               if (defaultValue.isEmpty() || value != defaultValue)
                {
                {
                   // Value differs.  Check whether it also differs from the
                   // Value differs.  Check whether it also differs from the
                   // value in the copy source if there is one.
                   // value in the copy source if there is one.
 
 
                   if (object->getCopySource())
                   if (object->getCopySource())
                   {
                   {
-                     const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
-                     if (!copySourceValue || dStricmp(copySourceValue, value) != 0)
+                     String copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
+                     if (copySourceValue.isEmpty() || copySourceValue != value)
                         mustUpdate = true;
                         mustUpdate = true;
-
-                     if (copySourceValue)
-                        dFree(copySourceValue);
                   }
                   }
                   else
                   else
                      mustUpdate = true;
                      mustUpdate = true;
@@ -1620,12 +1604,9 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
 
 
                   if (object->getCopySource())
                   if (object->getCopySource())
                   {
                   {
-                     const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
-                     if (copySourceValue && dStricmp(copySourceValue, value) != 0)
+                     String copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
+                     if (!copySourceValue.isEmpty() && copySourceValue != value)
                         mustUpdate = true;
                         mustUpdate = true;
-
-                     if (copySourceValue)
-                        dFree(copySourceValue);
                   }
                   }
                }
                }
 
 
@@ -1650,26 +1631,21 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
                      f->type == TypeSoundFilename)
                      f->type == TypeSoundFilename)
                   {
                   {
                      char fnBuf[1024];
                      char fnBuf[1024];
-                     Con::collapseScriptFilename(fnBuf, 1024, value);
+                     Con::collapseScriptFilename(fnBuf, 1024, value.c_str());
 
 
                      newLines.push_back(createNewProperty(f->pFieldname, fnBuf, f->elementCount > 1, j));
                      newLines.push_back(createNewProperty(f->pFieldname, fnBuf, f->elementCount > 1, j));
                   }
                   }
                   else if (f->type == TypeCommand)
                   else if (f->type == TypeCommand)
                   {
                   {
                      char cmdBuf[1024];
                      char cmdBuf[1024];
-                     expandEscape(cmdBuf, value);
+                     expandEscape(cmdBuf, value.c_str());
 
 
                      newLines.push_back(createNewProperty(f->pFieldname, cmdBuf, f->elementCount > 1, j));
                      newLines.push_back(createNewProperty(f->pFieldname, cmdBuf, f->elementCount > 1, j));
                   }
                   }
                   else
                   else
                      newLines.push_back(createNewProperty(f->pFieldname, value, f->elementCount > 1, j));
                      newLines.push_back(createNewProperty(f->pFieldname, value, f->elementCount > 1, j));
                }
                }
-
-               if (defaultValue)
-                  dFree(defaultValue);
             }
             }
-
-            dFree(value);
          }
          }
       }
       }
    }
    }
@@ -1812,15 +1788,6 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
    }
    }
 
 
    // Clean up the newLines memory
    // Clean up the newLines memory
-   for (U32 i = 0; i < newLines.size(); i++)
-   {
-      if (!isEmptyLine(newLines[i]) && !StringTable->lookup(newLines[i]))
-      {//don't try killing empty lines or lines that are in the string table
-         dFree(newLines[i]);
-      }
-      newLines[ i ] = NULL;
-   }
-
    newLines.clear();
    newLines.clear();
 
 
    SimSet* set = dynamic_cast<SimSet*>(object);
    SimSet* set = dynamic_cast<SimSet*>(object);

+ 2 - 2
Engine/source/console/persistenceManager.h

@@ -278,9 +278,9 @@ protected:
 
 
    // Write out properties
    // Write out properties
    // Returns the number of new lines added
    // Returns the number of new lines added
-   U32 writeProperties(const Vector<const char*>& properties, const U32 insertLine, const char* objectIndent);
+   U32 writeProperties(const Vector<String>& properties, const U32 insertLine, const char* objectIndent);
    // Write out a new object
    // Write out a new object
-   ParsedObject* writeNewObject(SimObject* object, const Vector<const char*>& properties, const U32 insertLine, ParsedObject* parentObject = NULL);
+   ParsedObject* writeNewObject(SimObject* object, const Vector<String>& properties, const U32 insertLine, ParsedObject* parentObject = NULL);
 
 
 public:
 public:
    PersistenceManager();
    PersistenceManager();

+ 1 - 1
Engine/source/environment/decalRoad.cpp

@@ -494,7 +494,7 @@ const char* DecalRoad::getSpecialFieldOut(StringTableEntry fieldName, const U32&
 
 
       char buffer[1024];
       char buffer[1024];
       dMemset(buffer, 0, 1024);
       dMemset(buffer, 0, 1024);
-      dSprintf(buffer, 1024, "%f %f %f %f", node.point.x, node.point.y, node.point.z, node.width);
+      dSprintf(buffer, 1024, "node = \"%f %f %f %f\";", node.point.x, node.point.y, node.point.z, node.width);
 
 
       return StringTable->insert(buffer);
       return StringTable->insert(buffer);
    }
    }

+ 1 - 1
Engine/source/environment/meshRoad.cpp

@@ -1197,7 +1197,7 @@ const char* MeshRoad::getSpecialFieldOut(StringTableEntry fieldName, const U32&
 
 
       return StringTable->insert(buffer);
       return StringTable->insert(buffer);
    }
    }
-   else if (fieldName == StringTable->insert("ProfileNode"))
+   else if (fieldName == StringTable->insert("ProfileNode") && mSideProfile.mNodes.size())
    {
    {
       Point3F nodePos = mSideProfile.mNodes[index].getPosition();
       Point3F nodePos = mSideProfile.mNodes[index].getPosition();
       U8 smooth, mtrl;
       U8 smooth, mtrl;

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

@@ -4,7 +4,13 @@ function AssetBrowser::setupCreateNewLevelAsset(%this)
    NewAssetPropertiesInspector.addField("LevelName", "Level Name", "String",  "Human-readable name of new level", "", "", %this.newAssetSettings);
    NewAssetPropertiesInspector.addField("LevelName", "Level Name", "String",  "Human-readable name of new level", "", "", %this.newAssetSettings);
    NewAssetPropertiesInspector.addField("levelPreviewImage", "Level Preview Image", "Image",  "Preview Image for the level", "", "", %this.newAssetSettings);
    NewAssetPropertiesInspector.addField("levelPreviewImage", "Level Preview Image", "Image",  "Preview Image for the level", "", "", %this.newAssetSettings);
    
    
-   NewAssetPropertiesInspector.addField("isSubScene", "Is SubScene", "bool",  "Is this levelAsset intended as a subScene", "", "", %this.newAssetSettings);
+   //If we forcefully set it elsewhere, adhere
+   if($createLevelAssetIsSubScene == true)
+      %this.newAssetSettings.isSubScene = true;
+   else
+      %this.newAssetSettings.isSubScene = false;
+   
+   NewAssetPropertiesInspector.addField("isSubScene", "Is SubScene", "bool", "Is this levelAsset intended as a subScene", %this.newAssetSettings.isSubScene, "", %this.newAssetSettings);
 
 
    NewAssetPropertiesInspector.endGroup();
    NewAssetPropertiesInspector.endGroup();
 }
 }
@@ -27,6 +33,7 @@ function AssetBrowser::createLevelAsset(%this)
    %tamlpath = %assetPath @ %assetName @ ".asset.taml";
    %tamlpath = %assetPath @ %assetName @ ".asset.taml";
    %levelPath = %assetPath @ %assetName @ %misExtension;
    %levelPath = %assetPath @ %assetName @ %misExtension;
    
    
+
    %asset = new LevelAsset()
    %asset = new LevelAsset()
    {
    {
       AssetName = %assetName;
       AssetName = %assetName;
@@ -55,7 +62,24 @@ function AssetBrowser::createLevelAsset(%this)
       echo("Unable to copy template level file!");
       echo("Unable to copy template level file!");
    }
    }
    
    
-   replaceInFile(%levelPath, "EditorTemplateLevel", %assetName);
+   if(%asset.isSubScene)
+   {
+      %fileObj = new FileObject();
+      if (!%fileObj.openForWrite(%levelPath)) 
+      {
+         echo("Unable to write subScene file!");
+      }
+      else
+      {
+         %fileObj.writeLine("");
+         %fileObj.close();
+         %fileObj.delete();  
+      }
+   }
+   else
+   {
+      replaceInFile(%levelPath, "EditorTemplateLevel", %assetName);
+   }
    
    
    //Generate the associated files
    //Generate the associated files
    DecalManagerSave( %assetPath @ %asset.DecalsFile );
    DecalManagerSave( %assetPath @ %asset.DecalsFile );
@@ -87,6 +111,8 @@ function AssetBrowser::setupCreateNewSubScene(%this)
 
 
 function AssetBrowser::editLevelAsset(%this, %assetDef)
 function AssetBrowser::editLevelAsset(%this, %assetDef)
 {
 {
+   echo("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+   echo(%assetDef @ ".isSubScene = " @ %assetDef.isSubScene);
    if(!%assetDef.isSubScene)
    if(!%assetDef.isSubScene)
       schedule( 1, 0, "EditorOpenMission", %assetDef);
       schedule( 1, 0, "EditorOpenMission", %assetDef);
 }
 }
@@ -157,7 +183,15 @@ function AssetBrowser::buildLevelAssetPreview(%this, %assetDef, %previewData)
 {
 {
    %previewData.assetName = %assetDef.assetName;
    %previewData.assetName = %assetDef.assetName;
    %previewData.assetPath = %assetDef.getLevelPath();
    %previewData.assetPath = %assetDef.getLevelPath();
-   %previewData.doubleClickCommand = "schedule( 1, 0, \"EditorOpenMission\", "@%assetDef@");";
+
+   if(%this.selectMode || %assetDef.isSubScene)
+   {
+      %previewData.doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );";
+   }
+   else
+   {
+      %previewData.doubleClickCommand = "schedule( 1, 0, \"EditorOpenMission\", "@%assetDef@");";
+   }
    
    
    %levelPreviewImage = %assetDef.PreviewImage;
    %levelPreviewImage = %assetDef.PreviewImage;
          
          
@@ -176,7 +210,10 @@ function AssetBrowser::buildLevelAssetPreview(%this, %assetDef, %previewData)
 
 
 function createAndAssignLevelAsset(%moduleName, %assetName)
 function createAndAssignLevelAsset(%moduleName, %assetName)
 {
 {
-   $createAndAssignField.apply(%moduleName @ ":" @ %assetName);
+   if(AssetDatabase.isDeclaredAsset(%moduleName))
+      $createAndAssignField.apply(%moduleName);
+   else
+      $createAndAssignField.apply(%moduleName @ ":" @ %assetName);
 }
 }
 
 
 function EWorldEditor::createSelectedAsSubScene( %this, %object )
 function EWorldEditor::createSelectedAsSubScene( %this, %object )

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

@@ -124,6 +124,8 @@ function AssetBrowser::setupCreateNewAsset(%this, %assetType, %moduleName, %call
       %command = %this @ ".setupCreateNew"@%assetType @"();";
       %command = %this @ ".setupCreateNew"@%assetType @"();";
       eval(%command);
       eval(%command);
    }
    }
+   
+   NewAssetPropertiesInspector.refresh();
 }
 }
 
 
 function NewAssetPropertiesInspector::updateNewAssetField(%this)
 function NewAssetPropertiesInspector::updateNewAssetField(%this)