2022-10-13 17:38:11 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# pragma once
# include "Metasound.h"
# include "MetasoundAssetManager.h"
2024-05-29 15:33:29 -04:00
# include "MetasoundDocumentBuilderRegistry.h"
2023-08-21 12:25:01 -04:00
# include "MetasoundFrontendDocumentIdGenerator.h"
2023-12-19 15:55:04 -05:00
# include "MetasoundFrontendRegistryKey.h"
2024-06-17 12:51:18 -04:00
# include "MetasoundGlobals.h"
2022-10-13 17:38:11 -04:00
# include "MetasoundUObjectRegistry.h"
2024-02-12 12:56:38 -05:00
# include "Misc/App.h"
2022-10-13 17:38:11 -04:00
# include "Serialization/Archive.h"
# if WITH_EDITORONLY_DATA
# include "Algo/Transform.h"
2024-05-30 18:56:24 -04:00
# include "MetasoundFrontendRegistryContainer.h"
2024-06-14 13:05:35 -04:00
# include "UObject/GarbageCollection.h"
2024-05-30 18:56:24 -04:00
# include "UObject/ObjectMacros.h"
2024-06-17 12:51:18 -04:00
# include "UObject/StrongObjectPtrTemplates.h"
2022-10-13 17:38:11 -04:00
# endif // WITH_EDITORONLY_DATA
2024-05-30 18:56:24 -04:00
namespace Metasound : : Engine
2022-10-13 17:38:11 -04:00
{
/** MetaSound Engine Asset helper provides routines for UObject based MetaSound assets.
* Any UObject deriving from FMetaSoundAssetBase should use these helper functions
* in their UObject overrides .
*/
2024-05-30 18:56:24 -04:00
struct FAssetHelper
2022-10-13 17:38:11 -04:00
{
2024-06-17 12:51:18 -04:00
static bool SerializationRequiresDeterminism ( bool bIsCooking )
2024-06-14 13:05:35 -04:00
{
2024-06-17 12:51:18 -04:00
return bIsCooking | | IsRunningCookCommandlet ( ) ;
2024-06-14 13:05:35 -04:00
}
2022-10-13 17:38:11 -04:00
# if WITH_EDITOR
2024-06-10 13:52:48 -04:00
static void PreDuplicate ( TScriptInterface < IMetaSoundDocumentInterface > MetaSound , FObjectDuplicationParameters & DupParams )
{
FDocumentBuilderRegistry : : GetChecked ( ) . SetEventLogVerbosity ( FDocumentBuilderRegistry : : ELogEvent : : DuplicateEntries , ELogVerbosity : : NoLogging ) ;
}
2024-05-08 14:53:53 -04:00
static void PostDuplicate ( TScriptInterface < IMetaSoundDocumentInterface > MetaSound , EDuplicateMode : : Type InDuplicateMode , FGuid & OutAssetClassID )
{
2024-06-10 13:52:48 -04:00
using namespace Engine ;
2024-05-29 15:33:29 -04:00
using namespace Frontend ;
2024-05-08 14:53:53 -04:00
if ( InDuplicateMode = = EDuplicateMode : : Normal )
{
2024-06-10 13:52:48 -04:00
UObject * MetaSoundObject = MetaSound . GetObject ( ) ;
check ( MetaSoundObject ) ;
FDocumentBuilderRegistry & BuilderRegistry = FDocumentBuilderRegistry : : GetChecked ( ) ;
UMetaSoundBuilderBase & DuplicateBuilder = BuilderRegistry . FindOrBeginBuilding ( * MetaSoundObject ) ;
FMetaSoundFrontendDocumentBuilder & DocBuilder = DuplicateBuilder . GetBuilder ( ) ;
const FMetasoundFrontendClassName DuplicateName = DocBuilder . GetConstDocumentChecked ( ) . RootGraph . Metadata . GetClassName ( ) ;
const FMetasoundFrontendClassName NewName = DocBuilder . GenerateNewClassName ( ) ;
2024-05-08 14:53:53 -04:00
ensureAlwaysMsgf ( IMetaSoundAssetManager : : GetChecked ( ) . TryGetAssetIDFromClassName ( NewName , OutAssetClassID ) , TEXT ( " Failed to retrieve newly duplicated MetaSoundClassName AssetID " ) ) ;
2024-06-10 13:52:48 -04:00
constexpr bool bForceUnregisterNodeClass = true ;
BuilderRegistry . FinishBuilding ( DuplicateName , MetaSound - > GetAssetPathChecked ( ) , bForceUnregisterNodeClass ) ;
BuilderRegistry . SetEventLogVerbosity ( FDocumentBuilderRegistry : : ELogEvent : : DuplicateEntries , ELogVerbosity : : All ) ;
2024-05-08 14:53:53 -04:00
}
}
2022-10-13 17:38:11 -04:00
template < typename TMetaSoundObject >
static void PostEditUndo ( TMetaSoundObject & InMetaSound )
{
InMetaSound . GetModifyContext ( ) . SetForceRefreshViews ( ) ;
2023-07-24 17:38:26 -04:00
2024-06-18 16:47:21 -04:00
const FMetasoundFrontendClassName & ClassName = InMetaSound . GetConstDocument ( ) . RootGraph . Metadata . GetClassName ( ) ;
Frontend : : IDocumentBuilderRegistry : : GetChecked ( ) . ReloadBuilder ( ClassName ) ;
2023-07-24 17:38:26 -04:00
2022-10-13 17:38:11 -04:00
if ( UMetasoundEditorGraphBase * Graph = Cast < UMetasoundEditorGraphBase > ( InMetaSound . GetGraph ( ) ) )
{
Graph - > RegisterGraphWithFrontend ( ) ;
}
}
template < typename TMetaSoundObject >
2023-12-19 15:55:04 -05:00
static void SetReferencedAssetClasses ( TMetaSoundObject & InMetaSound , TSet < Frontend : : IMetaSoundAssetManager : : FAssetInfo > & & InAssetClasses )
2022-10-13 17:38:11 -04:00
{
2023-12-19 15:55:04 -05:00
using namespace Frontend ;
2022-10-13 17:38:11 -04:00
InMetaSound . ReferencedAssetClassKeys . Reset ( ) ;
InMetaSound . ReferencedAssetClassObjects . Reset ( ) ;
for ( const IMetaSoundAssetManager : : FAssetInfo & AssetClass : InAssetClasses )
{
2023-10-12 16:37:45 -04:00
InMetaSound . ReferencedAssetClassKeys . Add ( AssetClass . RegistryKey . ToString ( ) ) ;
2022-10-13 17:38:11 -04:00
if ( UObject * Object = AssetClass . AssetPath . TryLoad ( ) )
{
InMetaSound . ReferencedAssetClassObjects . Add ( Object ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to load referenced asset %s from asset %s " ) , * AssetClass . AssetPath . ToString ( ) , * InMetaSound . GetPathName ( ) ) ;
}
}
}
# endif // WITH_EDITOR
2023-12-15 13:21:12 -05:00
template < typename TMetaSoundObject >
static FTopLevelAssetPath GetAssetPathChecked ( TMetaSoundObject & InMetaSound )
{
FTopLevelAssetPath Path ;
2024-01-08 17:02:57 -05:00
ensureAlwaysMsgf ( Path . TrySetPath ( & InMetaSound ) , TEXT ( " Failed to set TopLevelAssetPath from MetaSound '%s'. MetaSound must be highest level object in package. " ) , * InMetaSound . GetPathName ( ) ) ;
ensureAlwaysMsgf ( Path . IsValid ( ) , TEXT ( " Failed to set TopLevelAssetPath from MetaSound '%s'. This may be caused by calling this function when the asset is being destroyed. " ) , * InMetaSound . GetPathName ( ) ) ;
2023-12-15 13:21:12 -05:00
return Path ;
}
2022-10-13 17:38:11 -04:00
template < typename TMetaSoundObject >
static TArray < FMetasoundAssetBase * > GetReferencedAssets ( TMetaSoundObject & InMetaSound )
{
TArray < FMetasoundAssetBase * > ReferencedAssets ;
IMetasoundUObjectRegistry & UObjectRegistry = IMetasoundUObjectRegistry : : Get ( ) ;
for ( TObjectPtr < UObject > & Object : InMetaSound . ReferencedAssetClassObjects )
{
if ( FMetasoundAssetBase * Asset = UObjectRegistry . GetObjectAsAssetBase ( Object ) )
{
ReferencedAssets . Add ( Asset ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Referenced asset \" %s \" , referenced from \" %s \" , is not convertible to FMetasoundAssetBase " ) , * Object - > GetPathName ( ) , * InMetaSound . GetPathName ( ) ) ;
}
}
return ReferencedAssets ;
}
- Fix for attempting to access EngineSubsystem during MetaSound versioning (serialization), which can assert when apparently certain commands in certain contexts can attempt to preload assets prior to the init phase.
- Minor Fix for LocText duplication
#tests BuildCookRun, -game, version MetaSounds assets in editor, PIE
[FYI] bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL33084850
[FYI] Rob.Gay
Original CL Desc
-----------------------------------------------------------------
Version Metasound Document to include all ed data and make all Metasound EdGraph data transient
- Add input template nodes
- Add comment node data to document
- Keep references to member literal data (i.e. knob/slider ranges) in document metadata to ensure continued serialization and flexibility to add more editor-only fields and literal metadata
- Misc builder API updates, bug fixes and migration of controllers to builder API in anticipation of pages
- Sunset non-deterministic guid cvar
#rb phil.popp, helen.yang
[FYI] sondra.moyls
#tests Standard Automated Audio Tests, EngineTests, Offline QA Smoke pass, CPR, etc., extensive MetaSound Editor use, -game MetaSound qa levels, AudioUnitTests
#jira UE-194159
[CL 33102023 by rob gay in ue5-main branch]
2024-04-19 10:09:04 -04:00
static void PreSaveAsset ( FMetasoundAssetBase & InMetaSound , FObjectPreSaveContext InSaveContext )
2022-10-13 17:38:11 -04:00
{
# if WITH_EDITORONLY_DATA
2023-12-19 15:55:04 -05:00
using namespace Frontend ;
2022-10-13 17:38:11 -04:00
2022-11-17 12:31:19 -05:00
if ( IMetaSoundAssetManager * AssetManager = IMetaSoundAssetManager : : Get ( ) )
{
AssetManager - > WaitUntilAsyncLoadReferencedAssetsComplete ( InMetaSound ) ;
}
2024-06-14 13:05:35 -04:00
const bool bIsCooking = InSaveContext . IsCooking ( ) ;
2024-06-17 12:51:18 -04:00
const bool bCanEverExecute = Metasound : : CanEverExecuteGraph ( bIsCooking ) ;
2024-06-14 13:05:35 -04:00
if ( ! bCanEverExecute )
2022-10-13 17:38:11 -04:00
{
2024-06-17 12:51:18 -04:00
const bool bIsDeterministic = SerializationRequiresDeterminism ( bIsCooking ) ;
2024-06-14 13:05:35 -04:00
FDocumentIDGenerator : : FScopeDeterminism DeterminismScope ( bIsDeterministic ) ;
2024-06-17 12:51:18 -04:00
InMetaSound . UpdateAndRegisterForSerialization ( ) ;
- Fix for attempting to access EngineSubsystem during MetaSound versioning (serialization), which can assert when apparently certain commands in certain contexts can attempt to preload assets prior to the init phase.
- Minor Fix for LocText duplication
#tests BuildCookRun, -game, version MetaSounds assets in editor, PIE
[FYI] bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL33084850
[FYI] Rob.Gay
Original CL Desc
-----------------------------------------------------------------
Version Metasound Document to include all ed data and make all Metasound EdGraph data transient
- Add input template nodes
- Add comment node data to document
- Keep references to member literal data (i.e. knob/slider ranges) in document metadata to ensure continued serialization and flexibility to add more editor-only fields and literal metadata
- Misc builder API updates, bug fixes and migration of controllers to builder API in anticipation of pages
- Sunset non-deterministic guid cvar
#rb phil.popp, helen.yang
[FYI] sondra.moyls
#tests Standard Automated Audio Tests, EngineTests, Offline QA Smoke pass, CPR, etc., extensive MetaSound Editor use, -game MetaSound qa levels, AudioUnitTests
#jira UE-194159
[CL 33102023 by rob gay in ue5-main branch]
2024-04-19 10:09:04 -04:00
}
else if ( FApp : : CanEverRenderAudio ( ) )
{
if ( UMetasoundEditorGraphBase * MetaSoundGraph = Cast < UMetasoundEditorGraphBase > ( InMetaSound . GetGraph ( ) ) )
2024-04-18 23:43:05 -04:00
{
- Fix for attempting to access EngineSubsystem during MetaSound versioning (serialization), which can assert when apparently certain commands in certain contexts can attempt to preload assets prior to the init phase.
- Minor Fix for LocText duplication
#tests BuildCookRun, -game, version MetaSounds assets in editor, PIE
[FYI] bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL33084850
[FYI] Rob.Gay
Original CL Desc
-----------------------------------------------------------------
Version Metasound Document to include all ed data and make all Metasound EdGraph data transient
- Add input template nodes
- Add comment node data to document
- Keep references to member literal data (i.e. knob/slider ranges) in document metadata to ensure continued serialization and flexibility to add more editor-only fields and literal metadata
- Misc builder API updates, bug fixes and migration of controllers to builder API in anticipation of pages
- Sunset non-deterministic guid cvar
#rb phil.popp, helen.yang
[FYI] sondra.moyls
#tests Standard Automated Audio Tests, EngineTests, Offline QA Smoke pass, CPR, etc., extensive MetaSound Editor use, -game MetaSound qa levels, AudioUnitTests
#jira UE-194159
[CL 33102023 by rob gay in ue5-main branch]
2024-04-19 10:09:04 -04:00
// Uses graph flavor of register with frontend to update editor systems/asset editors in case editor is enabled.
2024-04-18 23:43:05 -04:00
MetaSoundGraph - > RegisterGraphWithFrontend ( ) ;
- Fix for attempting to access EngineSubsystem during MetaSound versioning (serialization), which can assert when apparently certain commands in certain contexts can attempt to preload assets prior to the init phase.
- Minor Fix for LocText duplication
#tests BuildCookRun, -game, version MetaSounds assets in editor, PIE
[FYI] bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL33084850
[FYI] Rob.Gay
Original CL Desc
-----------------------------------------------------------------
Version Metasound Document to include all ed data and make all Metasound EdGraph data transient
- Add input template nodes
- Add comment node data to document
- Keep references to member literal data (i.e. knob/slider ranges) in document metadata to ensure continued serialization and flexibility to add more editor-only fields and literal metadata
- Misc builder API updates, bug fixes and migration of controllers to builder API in anticipation of pages
- Sunset non-deterministic guid cvar
#rb phil.popp, helen.yang
[FYI] sondra.moyls
#tests Standard Automated Audio Tests, EngineTests, Offline QA Smoke pass, CPR, etc., extensive MetaSound Editor use, -game MetaSound qa levels, AudioUnitTests
#jira UE-194159
[CL 33102023 by rob gay in ue5-main branch]
2024-04-19 10:09:04 -04:00
InMetaSound . GetModifyContext ( ) . SetForceRefreshViews ( ) ;
2024-02-12 12:56:38 -05:00
}
2024-04-18 16:50:48 -04:00
}
- Fix for attempting to access EngineSubsystem during MetaSound versioning (serialization), which can assert when apparently certain commands in certain contexts can attempt to preload assets prior to the init phase.
- Minor Fix for LocText duplication
#tests BuildCookRun, -game, version MetaSounds assets in editor, PIE
[FYI] bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL33084850
[FYI] Rob.Gay
Original CL Desc
-----------------------------------------------------------------
Version Metasound Document to include all ed data and make all Metasound EdGraph data transient
- Add input template nodes
- Add comment node data to document
- Keep references to member literal data (i.e. knob/slider ranges) in document metadata to ensure continued serialization and flexibility to add more editor-only fields and literal metadata
- Misc builder API updates, bug fixes and migration of controllers to builder API in anticipation of pages
- Sunset non-deterministic guid cvar
#rb phil.popp, helen.yang
[FYI] sondra.moyls
#tests Standard Automated Audio Tests, EngineTests, Offline QA Smoke pass, CPR, etc., extensive MetaSound Editor use, -game MetaSound qa levels, AudioUnitTests
#jira UE-194159
[CL 33102023 by rob gay in ue5-main branch]
2024-04-19 10:09:04 -04:00
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " PreSaveAsset for MetaSound: (%s) is doing nothing because InSaveContext.IsCooking, IsRunningCommandlet, and FApp::CanEverRenderAudio were all false " )
, * InMetaSound . GetOwningAssetName ( ) ) ;
}
2022-10-13 17:38:11 -04:00
# endif // WITH_EDITORONLY_DATA
}
template < typename TMetaSoundObject >
static void SerializeToArchive ( TMetaSoundObject & InMetaSound , FArchive & InArchive )
{
2024-05-30 18:56:24 -04:00
# if WITH_EDITORONLY_DATA
2024-06-14 13:05:35 -04:00
using namespace Frontend ;
2024-05-30 18:56:24 -04:00
bool bVersionedAsset = false ;
2022-10-13 17:38:11 -04:00
if ( InArchive . IsLoading ( ) )
{
2024-05-30 18:56:24 -04:00
TStrongObjectPtr < UMetaSoundBuilderBase > Builder ;
2022-10-13 17:38:11 -04:00
{
2024-05-30 18:56:24 -04:00
FGCScopeGuard ScopeGuard ;
Builder . Reset ( & FDocumentBuilderRegistry : : GetChecked ( ) . FindOrBeginBuilding ( InMetaSound ) ) ;
2022-10-13 17:38:11 -04:00
}
2024-05-30 18:56:24 -04:00
2024-06-14 13:05:35 -04:00
{
const bool bIsCooking = InArchive . IsCooking ( ) ;
2024-06-17 12:51:18 -04:00
const bool bIsDeterministic = SerializationRequiresDeterminism ( bIsCooking ) ;
2024-06-14 13:05:35 -04:00
FDocumentIDGenerator : : FScopeDeterminism DeterminismScope ( bIsDeterministic ) ;
check ( Builder . IsValid ( ) ) ;
bVersionedAsset = InMetaSound . VersionAsset ( Builder - > GetBuilder ( ) ) ;
}
2024-05-30 18:56:24 -04:00
Builder - > ClearInternalFlags ( EInternalObjectFlags : : Async ) ;
2022-10-13 17:38:11 -04:00
}
2024-05-30 18:56:24 -04:00
if ( bVersionedAsset )
{
InMetaSound . SetVersionedOnLoad ( ) ;
}
# endif // WITH_EDITORONLY_DATA
2022-10-13 17:38:11 -04:00
}
template < typename TMetaSoundObject >
static void PostLoad ( TMetaSoundObject & InMetaSound )
{
2022-10-14 10:55:37 -04:00
using namespace Frontend ;
// Do not call asset manager on CDO objects which may be loaded before asset
// manager is set.
const bool bIsCDO = InMetaSound . HasAnyFlags ( RF_ClassDefaultObject ) ;
if ( ! bIsCDO )
{
2022-10-17 12:46:38 -04:00
if ( InMetaSound . GetAsyncReferencedAssetClassPaths ( ) . Num ( ) > 0 )
2022-10-14 10:55:37 -04:00
{
2024-05-08 14:53:53 -04:00
IMetaSoundAssetManager : : GetChecked ( ) . RequestAsyncLoadReferencedAssets ( InMetaSound ) ;
2022-10-14 10:55:37 -04:00
}
}
2022-10-13 17:38:11 -04:00
}
template < typename TMetaSoundObject >
static void OnAsyncReferencedAssetsLoaded ( TMetaSoundObject & InMetaSound , const TArray < FMetasoundAssetBase * > & InAsyncReferences )
{
for ( FMetasoundAssetBase * AssetBase : InAsyncReferences )
{
if ( AssetBase )
{
if ( UObject * OwningAsset = AssetBase - > GetOwningAsset ( ) )
{
InMetaSound . ReferencedAssetClassObjects . Add ( OwningAsset ) ;
InMetaSound . ReferenceAssetClassCache . Remove ( FSoftObjectPath ( OwningAsset ) ) ;
}
}
}
}
# if WITH_EDITORONLY_DATA
template < typename TMetaSoundObject >
2023-12-19 15:55:04 -05:00
static void SetMetaSoundRegistryAssetClassInfo ( TMetaSoundObject & InMetaSound , const Frontend : : FNodeClassInfo & InClassInfo )
2022-10-13 17:38:11 -04:00
{
2023-12-19 15:55:04 -05:00
using namespace Frontend ;
2022-10-13 17:38:11 -04:00
check ( AssetTags : : AssetClassID = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , AssetClassID ) ) ;
2022-10-26 15:28:04 -04:00
check ( AssetTags : : IsPreset = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , bIsPreset ) ) ;
2022-10-13 17:38:11 -04:00
check ( AssetTags : : RegistryInputTypes = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryInputTypes ) ) ;
check ( AssetTags : : RegistryOutputTypes = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryOutputTypes ) ) ;
check ( AssetTags : : RegistryVersionMajor = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryVersionMajor ) ) ;
check ( AssetTags : : RegistryVersionMinor = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryVersionMinor ) ) ;
bool bMarkDirty = InMetaSound . AssetClassID ! = InClassInfo . AssetClassID ;
bMarkDirty | = InMetaSound . RegistryVersionMajor ! = InClassInfo . Version . Major ;
bMarkDirty | = InMetaSound . RegistryVersionMinor ! = InClassInfo . Version . Minor ;
2022-10-26 15:28:04 -04:00
bMarkDirty | = InMetaSound . bIsPreset ! = InClassInfo . bIsPreset ;
2022-10-13 17:38:11 -04:00
InMetaSound . AssetClassID = InClassInfo . AssetClassID ;
InMetaSound . RegistryVersionMajor = InClassInfo . Version . Major ;
InMetaSound . RegistryVersionMinor = InClassInfo . Version . Minor ;
2022-10-26 15:28:04 -04:00
InMetaSound . bIsPreset = InClassInfo . bIsPreset ;
2022-10-13 17:38:11 -04:00
{
TArray < FString > InputTypes ;
Algo : : Transform ( InClassInfo . InputTypes , InputTypes , [ ] ( const FName & Name ) { return Name . ToString ( ) ; } ) ;
const FString TypeString = FString : : Join ( InputTypes , * AssetTags : : ArrayDelim ) ;
bMarkDirty | = InMetaSound . RegistryInputTypes ! = TypeString ;
InMetaSound . RegistryInputTypes = TypeString ;
}
{
TArray < FString > OutputTypes ;
Algo : : Transform ( InClassInfo . OutputTypes , OutputTypes , [ ] ( const FName & Name ) { return Name . ToString ( ) ; } ) ;
const FString TypeString = FString : : Join ( OutputTypes , * AssetTags : : ArrayDelim ) ;
bMarkDirty | = InMetaSound . RegistryOutputTypes ! = TypeString ;
InMetaSound . RegistryOutputTypes = TypeString ;
}
}
# endif // WITH_EDITORONLY_DATA
} ;
2024-05-30 18:56:24 -04:00
} // namespace Metasound::Engine