Merge pull request #1379 from Areloch/VariousSubSceneFixes

Various Subscene Fixes
This commit is contained in:
Brian Roberts 2025-02-06 12:16:49 -06:00 committed by GitHub
commit b47ffb2f28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 124 additions and 84 deletions

View file

@ -3,6 +3,8 @@
#include "gameMode.h"
#include "console/persistenceManager.h"
#include "console/script.h"
#include "environment/meshRoad.h"
#include "environment/river.h"
#include "scene/sceneRenderState.h"
#include "renderInstance/renderPassManager.h"
#include "gfx/gfxDrawUtil.h"
@ -29,7 +31,8 @@ SubScene::SubScene() :
mFreezeLoading(false),
mTickPeriodMS(1000),
mCurrTick(0),
mGlobalLayer(false)
mGlobalLayer(false),
mSaving(false)
{
mNetFlags.set(Ghostable | ScopeAlways);
@ -65,6 +68,7 @@ void SubScene::initPersistFields()
addGroup("SubScene");
addField("isGlobalLayer", TypeBool, Offset(mGlobalLayer, SubScene), "");
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.");
endGroup("SubScene");
@ -263,6 +267,9 @@ void SubScene::_onFileChanged(const Torque::Path& path)
if(mLevelAsset.isNull() || Torque::Path(mLevelAsset->getLevelPath()) != path)
return;
if (mSaving)
return;
AssertFatal(path == mLevelAsset->getLevelPath(), "Prefab::_onFileChanged - path does not match filename.");
_closeFile(false);
@ -336,6 +343,9 @@ void SubScene::load()
if (mFreezeLoading)
return;
if (mSaving)
return;
_loadFile(true);
mLoaded = true;
@ -362,6 +372,9 @@ void SubScene::unload()
if (mFreezeLoading)
return;
if (mSaving)
return;
if (isSelected())
{
mStartUnloadTimerMS = Sim::getCurrentTime();
@ -421,10 +434,15 @@ bool SubScene::save()
if (mLevelAsset.isNull())
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 (mStartUnloadTimerMS != -1)
mStartUnloadTimerMS = Sim::getCurrentTime();
mSaving = true;
PersistenceManager prMger;
StringTableEntry levelPath = mLevelAsset->getLevelPath();
@ -449,6 +467,11 @@ bool SubScene::save()
prMger.setDirty((*itr), levelPath);
}
}
if(dynamic_cast<MeshRoad*>(childObj) || dynamic_cast<River*>(childObj))
{
prMger.addRemoveField(childObj, "position");
}
}
prMger.saveDirty();
@ -466,6 +489,8 @@ bool SubScene::save()
//Finally, save
saveSuccess = mLevelAsset->saveAsset();
mSaving = false;
return saveSuccess;
}

View file

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

View file

@ -43,6 +43,7 @@
// Debug Profiling.
#include "platform/profiler.h"
#include "gfx/gfxDrawUtil.h"
#include "T3D/SubScene.h"
//-----------------------------------------------------------------------------
@ -479,8 +480,15 @@ GuiControl* GuiInspectorTypeLevelAssetPtr::constructEditControl()
// Create "Open in Editor" button
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);
char bitmapName[512] = "ToolsModule:iconAdd_image";

View file

@ -526,7 +526,7 @@ const char* ConvexShape::getSpecialFieldOut(StringTableEntry fieldName, const U3
char buffer[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,
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);
@ -541,7 +541,7 @@ const char* ConvexShape::getSpecialFieldOut(StringTableEntry fieldName, const U3
char buffer[1024];
dMemset(buffer, 0, 1024);
dSprintf(buffer, 1024, "%s", mSurfaceTextures[index].getMaterial());
dSprintf(buffer, 1024, "surfaceTexture = \"%s\";", mSurfaceTextures[index].getMaterial());
return StringTable->insert(buffer);
}

View file

@ -1224,13 +1224,13 @@ void PersistenceManager::removeField(const ParsedProperty& prop)
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;
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)
continue;
@ -1248,7 +1248,7 @@ U32 PersistenceManager::writeProperties(const Vector<const char*>& properties, c
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;
@ -1353,7 +1353,7 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
if (!defaultObject)
return;
Vector<const char*> newLines;
Vector<String> newLines;
ParsedObject* parsedObject = findParsedObject(object, parentObject);
@ -1392,10 +1392,10 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
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
if (!value)
if (value.isEmpty())
continue;
// 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))
{
removeField(parsedObject->properties[propertyIndex]);
dFree(value);
continue;
}
// Run the parsed value through the console system conditioners so
// 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.
//
@ -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
// 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);
}
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
if (findRemoveField(object, f->pFieldname, j))
{
dFree(value);
continue;
}
@ -1452,20 +1450,17 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
// then we need to compare against the default value
// 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 in the copy source if there is one.
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;
if (copySourceValue)
dFree(copySourceValue);
}
else
mustUpdate = true;
@ -1478,12 +1473,9 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
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;
if (copySourceValue)
dFree(copySourceValue);
}
}
@ -1498,11 +1490,8 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
// value then add it to the ParsedObject's newLines
if (mustUpdate)
{
newLines.push_back(String(value).c_str());
newLines.push_back(value);
}
if (defaultValue)
dFree(defaultValue);
}
//dFree(value);
@ -1512,10 +1501,10 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
{
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
if (!value)
if (value.isEmpty())
continue;
// 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];
// 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]);
dFree(value);
continue;
}
// Run the parsed value through the console system conditioners so
// 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.
//
@ -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
// 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);
}
@ -1563,14 +1551,14 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
f->type == TypeSoundFilename)
{
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);
}
else if (f->type == TypeCommand || f->type == TypeString || f->type == TypeRealString)
{
char cmdBuf[1024];
expandEscape(cmdBuf, value);
expandEscape(cmdBuf, value.c_str());
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, cmdBuf, true);
}
@ -1582,9 +1570,8 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
else
{
// 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;
}
@ -1594,20 +1581,17 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
// then we need to compare against the default value
// 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 in the copy source if there is one.
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;
if (copySourceValue)
dFree(copySourceValue);
}
else
mustUpdate = true;
@ -1620,12 +1604,9 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
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;
if (copySourceValue)
dFree(copySourceValue);
}
}
@ -1650,26 +1631,21 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
f->type == TypeSoundFilename)
{
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));
}
else if (f->type == TypeCommand)
{
char cmdBuf[1024];
expandEscape(cmdBuf, value);
expandEscape(cmdBuf, value.c_str());
newLines.push_back(createNewProperty(f->pFieldname, cmdBuf, f->elementCount > 1, j));
}
else
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
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();
SimSet* set = dynamic_cast<SimSet*>(object);

View file

@ -278,9 +278,9 @@ protected:
// Write out properties
// 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
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:
PersistenceManager();

View file

@ -494,7 +494,7 @@ const char* DecalRoad::getSpecialFieldOut(StringTableEntry fieldName, const U32&
char buffer[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);
}

View file

@ -1197,7 +1197,7 @@ const char* MeshRoad::getSpecialFieldOut(StringTableEntry fieldName, const U32&
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();
U8 smooth, mtrl;

View file

@ -4,7 +4,13 @@ function AssetBrowser::setupCreateNewLevelAsset(%this)
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("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();
}
@ -27,6 +33,7 @@ function AssetBrowser::createLevelAsset(%this)
%tamlpath = %assetPath @ %assetName @ ".asset.taml";
%levelPath = %assetPath @ %assetName @ %misExtension;
%asset = new LevelAsset()
{
AssetName = %assetName;
@ -55,7 +62,24 @@ function AssetBrowser::createLevelAsset(%this)
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
DecalManagerSave( %assetPath @ %asset.DecalsFile );
@ -87,6 +111,8 @@ function AssetBrowser::setupCreateNewSubScene(%this)
function AssetBrowser::editLevelAsset(%this, %assetDef)
{
echo("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
echo(%assetDef @ ".isSubScene = " @ %assetDef.isSubScene);
if(!%assetDef.isSubScene)
schedule( 1, 0, "EditorOpenMission", %assetDef);
}
@ -157,7 +183,15 @@ function AssetBrowser::buildLevelAssetPreview(%this, %assetDef, %previewData)
{
%previewData.assetName = %assetDef.assetName;
%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;
@ -176,7 +210,10 @@ function AssetBrowser::buildLevelAssetPreview(%this, %assetDef, %previewData)
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 )

View file

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