From 0ca66b99db81a3363dde1ea6dbc4d84e5a764467 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 5 Sep 2021 03:43:41 -0500 Subject: [PATCH] Added fix so if a looping sound is preview-playing in the AB and you edit the properties, it doesn't try to reload the asset while it's playing, causing a crash Added console method for looking up a soundAsset by filename Added initial pass of project importer for sound assets content --- Engine/source/T3D/assets/SoundAsset.cpp | 8 + Engine/source/sfx/sfxSource.cpp | 11 +- .../scripts/assetTypes/shape.tscript | 4 + .../scripts/assetTypes/sound.tscript | 6 + .../assetBrowser/scripts/editAsset.tscript | 5 + .../pre40/T3Dpre4ProjectImporter.tscript | 168 ++++++++++++++++++ .../scripts/projectImporter.tscript | 115 +++++++++++- 7 files changed, 309 insertions(+), 8 deletions(-) diff --git a/Engine/source/T3D/assets/SoundAsset.cpp b/Engine/source/T3D/assets/SoundAsset.cpp index d4e9a745a..d00c0dbe2 100644 --- a/Engine/source/T3D/assets/SoundAsset.cpp +++ b/Engine/source/T3D/assets/SoundAsset.cpp @@ -343,6 +343,14 @@ DefineEngineMethod(SoundAsset, playSound, S32, (Point3F position), (Point3F::Zer return 0; } +#ifdef TORQUE_TOOLS +DefineEngineStaticMethod(SoundAsset, getAssetIdByFilename, const char*, (const char* filePath), (""), + "Queries the Asset Database to see if any asset exists that is associated with the provided file path.\n" + "@return The AssetId of the associated asset, if any.") +{ + return SoundAsset::getAssetIdByFileName(StringTable->insert(filePath)); +} +#endif IMPLEMENT_CONOBJECT(GuiInspectorTypeSoundAssetPtr); ConsoleDocClass(GuiInspectorTypeSoundAssetPtr, diff --git a/Engine/source/sfx/sfxSource.cpp b/Engine/source/sfx/sfxSource.cpp index abc5b35e1..9b776af94 100644 --- a/Engine/source/sfx/sfxSource.cpp +++ b/Engine/source/sfx/sfxSource.cpp @@ -791,6 +791,9 @@ void SFXSource::_setStatus( SFXStatus status ) void SFXSource::_updateVolume( const MatrixF& listener ) { + if (!mDescription) + return; + // Handle fades (compute mFadedVolume). mFadedVolume = mPreFadeVolume; @@ -919,13 +922,19 @@ void SFXSource::_updateVolume( const MatrixF& listener ) void SFXSource::_updatePitch() { + if (!mDescription) + return; + mEffectivePitch = mModulativePitch * mPitch; } //----------------------------------------------------------------------------- void SFXSource::_updatePriority() -{ +{ + if (!mDescription) + return; + mEffectivePriority = mPriority * mModulativePriority; SFXSource* group = getSourceGroup(); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript index 4bf17453a..8ca2a21ed 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript @@ -42,6 +42,10 @@ function AssetBrowser::editShapeAsset(%this, %assetDef) ShapeEditorPlugin.openShapeAsset(%assetDef); } +function AssetBrowser::onShapeAssetChanged(%this, %assetDef) +{ +} + function AssetBrowser::deleteShapeAsset(%this, %assetDef) { diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript index 77eb1a7cd..3322964bc 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript @@ -5,6 +5,12 @@ function AssetBrowser::editSoundAsset(%this, %assetDef) $PreviewSoundSource = %assetDef.playSound(); } +function AssetBrowser::onSoundAssetChanged(%this, %assetDef) +{ + if (isObject($PreviewSoundSource)) + sfxStop($PreviewSoundSource); +} + function AssetBrowser::buildSoundAssetPreview(%this, %assetDef, %previewData) { %previewData.assetName = %assetDef.assetName; diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript index b031c6124..13269cb25 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript @@ -6,6 +6,11 @@ function AssetBrowser_editAsset::saveAsset(%this) AssetBrowser.reloadAsset(%this.editedAssetId); AssetBrowser.refresh(); + + %assetType = AssetDatabase.getAssetType(%this.editedAssetId); + %assetDef = AssetDatabase.acquireAsset(%this.editedAssetId); + AssetBrowser.call("on" @ %assetType @ "Changed", %assetDef); + AssetDatabase.releaseAsset(%this.editedAssetId); Canvas.popDialog(AssetBrowser_editAsset); } diff --git a/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript b/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript index 735e8dd66..4c6ede9fb 100644 --- a/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript +++ b/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript @@ -838,6 +838,7 @@ T3Dpre4ProjectImporter::genProcessor("afxBillboardData", "texture textureAsset") T3Dpre4ProjectImporter::genProcessor("afxModelData", "shapeName shapeAsset shapeFile shapeAsset"); T3Dpre4ProjectImporter::genProcessor("afxZodiacData", "texture textureAsset"); T3Dpre4ProjectImporter::genProcessor("afxZodiacPlaneData", "texture textureAsset"); +T3Dpre4ProjectImporter::genProcessor("sfxEmitter", "track soundAsset filename soundAsset"); //============================================================================== // Levels //============================================================================== @@ -1064,6 +1065,173 @@ function T3Dpre4ProjectImporter::processTerrainMaterialObject(%this, %file, %obj //============================================================================== T3Dpre4ProjectImporter::genProcessor("PostEffect", "texture textureAsset"); +//============================================================================== +// Sounds +// Sounds are a little weird because there's so much data tied up in a given sound +// source. So our approach is find old SFXProfiles and process those into sound assets +// by cross-referencing the filename for existing asset definitions. +// Using existing SFXProfiles allows us to also injest the descriptions, giving us +// our meta-properties on the sound asset itself. +//============================================================================== +function T3Dpre4ProjectImporter::processSFXProfileLine(%this, %line) +{ + return %line; +} + +function T3Dpre4ProjectImporter::processSFXProfileObject(%this, %file, %objectName) +{ + %soundFilename = findObjectField("filename"); + + %soundFilename = sanitizeFilename(%soundFilename); + + %soundAsset = SoundAsset::getAssetIdByFilename(%soundFilename); + + //Throw a warn that this file's already been claimed and move on + if(%soundAsset !$= "") + { + error("T3Dpre4ProjectImporter::processSFXProfileObject() - attempting to process SFXProfile " @ %objectName + @ " but its filename is already associated to another sound asset."); + return false; + } + //Otherwise, process it into an asset + else + { + %assetName = %objectName; + + %moduleName = AssetBrowser.dirHandler.getModuleFromAddress(%soundFilename).ModuleId; + + %assetPath = filePath(%soundFilename) @ "/"; + + %tamlpath = %assetPath @ %assetName @ ".asset.taml"; + + if(isFile(%tamlpath)) + { + error("T3Dpre4ProjectImporter::processSFXProfileObject() - Failed to create as taml file already exists: " @ %soundFilename); + return false; + } + + %asset = new SoundAsset() + { + AssetName = %assetName; + versionId = 1; + shaderData = ""; + soundFile = fileBase(%soundFilename) @ fileExt(%soundFilename); + }; + + %descriptionName = findObjectField("description"); + + if(%descriptionName !$= "") + { + //Optimization, see if we already have this description by happenstance + if(isObject(%descriptionName)) + { + %asset.sourceGroup = %descriptionName.sourceGroup; + %asset.volume = %descriptionName.volume; + %asset.pitch = %descriptionName.pitch; + %asset.isLooping = %descriptionName.isLooping; + %asset.priority = %descriptionName.priority; + %asset.useHardware = %descriptionName.useHardware; + %asset.is3D = %descriptionName.is3D; + %asset.minDistance = %descriptionName.minDistance; + %asset.maxDistance = %descriptionName.maxDistance; + %asset.scatterDistance = %descriptionName.scatterDistance; + %asset.coneInsideAngle = %descriptionName.coneInsideAngle; + %asset.coneOutsideAngle = %descriptionName.coneOutsideAngle; + %asset.coneOutsideVolume = %descriptionName.coneOutsideVolume; + %asset.rolloffFactor = %descriptionName.rolloffFactor; + %asset.isStreaming = %descriptionName.isStreaming; + } + else + { + %objFileFinder = findObjectInFiles(%descriptionName); + if(%objFileFinder !$= "") + { + %valueArray = new ArrayObject(); + + %valueArray.add("sourceGroup" SPC findObjectField("sourceGroup", %objFileFinder)); + %valueArray.add("volume" SPC findObjectField("volume", %objFileFinder)); + %valueArray.add("pitch" SPC findObjectField("pitch", %objFileFinder)); + %valueArray.add("isLooping" SPC findObjectField("isLooping", %objFileFinder)); + %valueArray.add("priority" SPC findObjectField("priority", %objFileFinder)); + %valueArray.add("useHardware" SPC findObjectField("useHardware", %objFileFinder)); + %valueArray.add("is3D" SPC findObjectField("is3D", %objFileFinder)); + %valueArray.add("minDistance" SPC findObjectField("minDistance", %objFileFinder)); + %valueArray.add("maxDistance" SPC findObjectField("maxDistance", %objFileFinder)); + %valueArray.add("scatterDistance" SPC findObjectField("scatterDistance", %objFileFinder)); + %valueArray.add("coneInsideAngle" SPC findObjectField("coneInsideAngle", %objFileFinder)); + %valueArray.add("coneOutsideAngle" SPC findObjectField("coneOutsideAngle", %objFileFinder)); + %valueArray.add("coneOutsideVolume" SPC findObjectField("coneOutsideVolume", %objFileFinder)); + %valueArray.add("rolloffFactor" SPC findObjectField("rolloffFactor", %objFileFinder)); + %valueArray.add("isStreaming" SPC findObjectField("isStreaming", %objFileFinder)); + + %objFileFinder.delete(); + + for(%v=0; %v < %valueArray.Count(); %v++) + { + %varSet = %valueArray.getKey(%v); + %var = getWord(%varSet, 0); + %varVal = getWord(%varSet, 1); + + if(%varVal !$= "") + %asset.setFieldValue(%var, %varVal); + } + } + } + } + + TamlWrite(%asset, %tamlpath); + + %moduleDef = ModuleDatabase.findModule(%moduleName, 1); + %success = AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); + + if(!%success) + return false; + } + + //Now mark the original SFXProfile for removal from the file as it's redundant + //now that we have the asset def + + /*if(%matAsset $= "" || %matAsset $= "Core_Rendering:NoMaterial") + { + %assetName = %objectName; + + %moduleName = AssetBrowser.dirHandler.getModuleFromAddress(%file).ModuleId; + + %assetPath = filePath(%file) @ "/"; + + %tamlpath = %assetPath @ %assetName @ ".asset.taml"; + + if(isFile(%tamlpath)) + { + error("T3Dpre4ProjectImporter::processMaterialObject() - Failed to create as taml file already exists: " @ %file); + return false; + } + + %asset = new MaterialAsset() + { + AssetName = %assetName; + versionId = 1; + shaderData = ""; + materialDefinitionName = %assetName; + scriptFile = fileBase(%file); + }; + + TamlWrite(%asset, %tamlpath); + + %moduleDef = ModuleDatabase.findModule(%moduleName, 1); + %success = AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); + + if(!%success) + return false; + }*/ + + return true; +} + +function T3Dpre4ProjectImporter::processAudioProfileObject(%this, %file, %objectName) +{ + return %this.processSFXProfileObject(%file, %objectName); +} //============================================================================== // Misc Utility functions diff --git a/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript b/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript index 05a0847f4..d49e4eac4 100644 --- a/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript +++ b/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript @@ -416,7 +416,7 @@ function sanitizeFilename(%file) %sanitizedName = sanitizeString(%targetName); if(startsWith(%sanitizedName, "_")) { - %sanitizedName = substr(%sanitizedName, 1, -1); + %sanitizedName = getSubStr(%sanitizedName, 1, -1); } if(%sanitizedName !$= %targetName) { @@ -472,6 +472,12 @@ function testFilenameExtensions(%filename) return %filename @ ".dae"; else if(isFile(%filename @ ".dds")) return %filename @ ".dds"; + else if(isFile(%filename @ ".ogg")) + return %filename @ ".ogg"; + else if(isFile(%filename @ ".wav")) + return %filename @ ".wav"; + else if(isFile(%filename @ ".mp3")) + return %filename @ ".dds"; return %filename; } @@ -659,11 +665,14 @@ function findObjectName(%line, %createWord) return %objectName; } -function findObjectField(%fieldName) +function findObjectField(%fieldName, %fileObj) { + if(%fileObj $= "") + %fileObj = $ProjectImporter::fileObject; + %value = ""; %peekLineOffset = 0; - %peekLine = $ProjectImporter::fileObject.peekLine(%peekLineOffset); + %peekLine = %fileObj.peekLine(%peekLineOffset); while(!strIsMatchExpr("*};*", %peekLine) && !strIsMatchExpr("*singleton*(*)*", %peekLine) && !strIsMatchExpr("*new*(*)*", %peekLine) && @@ -671,7 +680,7 @@ function findObjectField(%fieldName) !strIsMatchExpr("\n", %peekLine) && !strIsMatchExpr("\r", %peekLine)) { - if(strpos(%peekLine, %fieldName) != -1) + if(strpos(strlwr(%peekLine), strlwr(%fieldName)) != -1) { %value = ""; %pos = strpos(%peekLine, "= \""); @@ -682,8 +691,7 @@ function findObjectField(%fieldName) %value = getSubStr(%peekLine, %pos+3, %endPos-%pos-3); break; } - else - { + %pos = strpos(%peekLine, "=\""); if(%pos != -1) { @@ -692,16 +700,109 @@ function findObjectField(%fieldName) %value = getSubStr(%peekLine, %pos+2, %endPos-%pos-2); break; } + + %pos = strpos(%peekLine, "= "); + if(%pos != -1) + { + %endPos = strpos(%peekLine, ";", %pos); + + %value = getSubStr(%peekLine, %pos+2, %endPos-%pos-2); + break; + } + + %pos = strpos(%peekLine, "="); + if(%pos != -1) + { + %endPos = strpos(%peekLine, ";", %pos); + + %value = getSubStr(%peekLine, %pos+2, %endPos-%pos-2); + break; } } %peekLineOffset++; - %peekLine = $ProjectImporter::fileObject.peekLine(%peekLineOffset); + %peekLine = %fileObj.peekLine(%peekLineOffset); } return %value; } +function findObjectInFiles(%objectName) +{ + //First, wipe out any files inside the folder first + %file = findFirstFileMultiExpr( "*.*", true); + + %fileObj = new FileObject(); + + while( %file !$= "" ) + { + %filename = fileName(%file); + %fileBase = fileBase(%file); + %fileExt = fileExt(%file); + %filePath = filePath(%file); + + if ( %fileObj.openForRead( %file ) ) + { + %lineNum = 0; + while ( !%fileObj.isEOF() ) + { + %line = %fileObj.readLine(); + %trimmedLine = trim(%line); + + if(strIsMatchExpr("*new*(*)*", %line) && strpos(%line, "::") == -1) + { + %className = findObjectClass(%line, "new"); + if (%className $= "") continue; + + %objName = findObjectName(%line, "new"); + + if(%objectName $= %objName) + { + return %fileObj; + } + } + else if(strIsMatchExpr("*datablock*(*)*", %line) && strpos(%line, "::") == -1) + { + %className = findObjectClass(%line, "datablock"); + if (%className $= "") continue; + + %objName = findObjectName(%line, "datablock"); + + if(%objectName $= %objName) + { + return %fileObj; + } + } + else if(strIsMatchExpr("*singleton*(*)*", %line) && strpos(%line, "::") == -1) + { + %className = findObjectClass(%line, "singleton"); + if (%className $= "") continue; + + %objName = findObjectName(%line, "singleton"); + + if(%objectName $= %objName) + { + return %fileObj; + } + } + + %lineNum++; + } + + %fileObj.close(); + } + else + { + error("findObjectInFiles() - File not able to be opened: " @ %file); + } + + %file = findNextFileMultiExpr( "*.*" ); + } + + %fileObj.delete(); + + return ""; +} //============================================================================== //Shape Importing //==============================================================================